LCOV - code coverage report
Current view: top level - layout/style - Loader.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 593 1083 54.8 %
Date: 2017-07-14 16:53:18 Functions: 34 58 58.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  * vim: ft=cpp tw=78 sw=2 et ts=2
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * This Original Code has been modified by IBM Corporation.
       9             :  * Modifications made by IBM described herein are Copyright (c)
      10             :  * International Business Machines Corporation, 2000.  Modifications
      11             :  * to Mozilla code or documentation identified per MPL Section 3.3
      12             :  *
      13             :  * Date             Modified by     Description of modification
      14             :  * 04/20/2000       IBM Corp.      OS/2 VisualAge build.
      15             :  */
      16             : 
      17             : /* loading of CSS style sheets using the network APIs */
      18             : 
      19             : #include "mozilla/css/Loader.h"
      20             : 
      21             : #include "mozilla/ArrayUtils.h"
      22             : #include "mozilla/dom/DocGroup.h"
      23             : #include "mozilla/IntegerPrintfMacros.h"
      24             : #include "mozilla/LoadInfo.h"
      25             : #include "mozilla/MemoryReporting.h"
      26             : #include "mozilla/StyleSheetInlines.h"
      27             : #include "mozilla/SystemGroup.h"
      28             : #include "nsIRunnable.h"
      29             : #include "nsIUnicharStreamLoader.h"
      30             : #include "nsSyncLoadService.h"
      31             : #include "nsCOMPtr.h"
      32             : #include "nsString.h"
      33             : #include "nsIContent.h"
      34             : #include "nsIDocument.h"
      35             : #include "nsIDOMNode.h"
      36             : #include "nsIDOMDocument.h"
      37             : #include "nsIURI.h"
      38             : #include "nsNetUtil.h"
      39             : #include "nsIProtocolHandler.h"
      40             : #include "nsContentUtils.h"
      41             : #include "nsIScriptSecurityManager.h"
      42             : #include "nsContentPolicyUtils.h"
      43             : #include "nsIHttpChannel.h"
      44             : #include "nsIHttpChannelInternal.h"
      45             : #include "nsIClassOfService.h"
      46             : #include "nsIScriptError.h"
      47             : #include "nsMimeTypes.h"
      48             : #include "nsIStyleSheetLinkingElement.h"
      49             : #include "nsICSSLoaderObserver.h"
      50             : #include "nsCSSParser.h"
      51             : #include "mozilla/css/ImportRule.h"
      52             : #include "nsThreadUtils.h"
      53             : #include "nsGkAtoms.h"
      54             : #include "nsIThreadInternal.h"
      55             : #include "nsINetworkPredictor.h"
      56             : #include "mozilla/dom/MediaList.h"
      57             : #include "mozilla/dom/ShadowRoot.h"
      58             : #include "mozilla/dom/URL.h"
      59             : #include "mozilla/AsyncEventDispatcher.h"
      60             : #include "mozilla/ServoBindings.h"
      61             : #include "mozilla/StyleSheet.h"
      62             : #include "mozilla/StyleSheetInlines.h"
      63             : #include "mozilla/ConsoleReportCollector.h"
      64             : #include "mozilla/ServoUtils.h"
      65             : 
      66             : #ifdef MOZ_XUL
      67             : #include "nsXULPrototypeCache.h"
      68             : #endif
      69             : 
      70             : #include "nsIDOMStyleSheet.h"
      71             : #include "nsError.h"
      72             : 
      73             : #include "nsIContentSecurityPolicy.h"
      74             : #include "mozilla/dom/SRICheck.h"
      75             : 
      76             : #include "mozilla/Encoding.h"
      77             : 
      78             : using namespace mozilla::dom;
      79             : 
      80             : /**
      81             :  * OVERALL ARCHITECTURE
      82             :  *
      83             :  * The CSS Loader gets requests to load various sorts of style sheets:
      84             :  * inline style from <style> elements, linked style, @import-ed child
      85             :  * sheets, non-document sheets.  The loader handles the following tasks:
      86             :  * 1) Creation of the actual style sheet objects: CreateSheet()
      87             :  * 2) setting of the right media, title, enabled state, etc on the
      88             :  *    sheet: PrepareSheet()
      89             :  * 3) Insertion of the sheet in the proper cascade order:
      90             :  *    InsertSheetInDoc() and InsertChildSheet()
      91             :  * 4) Load of the sheet: LoadSheet() including security checks
      92             :  * 5) Parsing of the sheet: ParseSheet()
      93             :  * 6) Cleanup: SheetComplete()
      94             :  *
      95             :  * The detailed documentation for these functions is found with the
      96             :  * function implementations.
      97             :  *
      98             :  * The following helper object is used:
      99             :  *    SheetLoadData -- a small class that is used to store all the
     100             :  *                     information needed for the loading of a sheet;
     101             :  *                     this class handles listening for the stream
     102             :  *                     loader completion and also handles charset
     103             :  *                     determination.
     104             :  */
     105             : 
     106             : namespace mozilla {
     107             : namespace css {
     108             : 
     109             : /*********************************************
     110             :  * Data needed to properly load a stylesheet *
     111             :  *********************************************/
     112             : 
     113             : static_assert(eAuthorSheetFeatures == 0 &&
     114             :               eUserSheetFeatures == 1 &&
     115             :               eAgentSheetFeatures == 2,
     116             :               "sheet parsing mode constants won't fit "
     117             :               "in SheetLoadData::mParsingMode");
     118             : 
     119             : class SheetLoadData final : public nsIRunnable,
     120             :                             public nsIUnicharStreamLoaderObserver,
     121             :                             public nsIThreadObserver
     122             : {
     123             : protected:
     124             :   virtual ~SheetLoadData(void);
     125             : 
     126             : public:
     127             :   // Data for loading a sheet linked from a document
     128             :   SheetLoadData(Loader* aLoader,
     129             :                 const nsAString& aTitle,
     130             :                 nsIURI* aURI,
     131             :                 StyleSheet* aSheet,
     132             :                 nsIStyleSheetLinkingElement* aOwningElement,
     133             :                 bool aIsAlternate,
     134             :                 nsICSSLoaderObserver* aObserver,
     135             :                 nsIPrincipal* aLoaderPrincipal,
     136             :                 nsINode* aRequestingNode);
     137             : 
     138             :   // Data for loading a sheet linked from an @import rule
     139             :   SheetLoadData(Loader* aLoader,
     140             :                 nsIURI* aURI,
     141             :                 StyleSheet* aSheet,
     142             :                 SheetLoadData* aParentData,
     143             :                 nsICSSLoaderObserver* aObserver,
     144             :                 nsIPrincipal* aLoaderPrincipal,
     145             :                 nsINode* aRequestingNode);
     146             : 
     147             :   // Data for loading a non-document sheet
     148             :   SheetLoadData(Loader* aLoader,
     149             :                 nsIURI* aURI,
     150             :                 StyleSheet* aSheet,
     151             :                 bool aSyncLoad,
     152             :                 bool aUseSystemPrincipal,
     153             :                 const nsCString& aCharset,
     154             :                 nsICSSLoaderObserver* aObserver,
     155             :                 nsIPrincipal* aLoaderPrincipal,
     156             :                 nsINode* aRequestingNode);
     157             : 
     158             :   already_AddRefed<nsIURI> GetReferrerURI();
     159             : 
     160             :   void ScheduleLoadEventIfNeeded(nsresult aStatus);
     161             : 
     162             :   NS_DECL_ISUPPORTS
     163             :   NS_DECL_NSIRUNNABLE
     164             :   NS_DECL_NSITHREADOBSERVER
     165             :   NS_DECL_NSIUNICHARSTREAMLOADEROBSERVER
     166             : 
     167             :   // Hold a ref to the CSSLoader so we can call back to it to let it
     168             :   // know the load finished
     169             :   RefPtr<Loader>           mLoader;
     170             : 
     171             :   // Title needed to pull datas out of the pending datas table when
     172             :   // the preferred title is changed
     173             :   nsString                   mTitle;
     174             : 
     175             :   // Charset we decided to use for the sheet
     176             :   nsCString                  mCharset;
     177             : 
     178             :   // URI we're loading.  Null for inline sheets
     179             :   nsCOMPtr<nsIURI>           mURI;
     180             : 
     181             :   // Should be 1 for non-inline sheets.
     182             :   uint32_t                   mLineNumber;
     183             : 
     184             :   // The sheet we're loading data for
     185             :   RefPtr<StyleSheet> mSheet;
     186             : 
     187             :   // Linked list of datas for the same URI as us
     188             :   SheetLoadData*             mNext;  // strong ref
     189             : 
     190             :   // Load data for the sheet that @import-ed us if we were @import-ed
     191             :   // during the parse
     192             :   RefPtr<SheetLoadData>    mParentData;
     193             : 
     194             :   // Number of sheets we @import-ed that are still loading
     195             :   uint32_t                   mPendingChildren;
     196             : 
     197             :   // mSyncLoad is true when the load needs to be synchronous -- right
     198             :   // now only for LoadSheetSync and children of sync loads.
     199             :   bool                       mSyncLoad : 1;
     200             : 
     201             :   // mIsNonDocumentSheet is true if the load was triggered by LoadSheetSync or
     202             :   // LoadSheet or an @import from such a sheet.  Non-document sheet loads can
     203             :   // proceed even if we have no document.
     204             :   bool                       mIsNonDocumentSheet : 1;
     205             : 
     206             :   // mIsLoading is true from the moment we are placed in the loader's
     207             :   // "loading datas" table (right after the async channel is opened)
     208             :   // to the moment we are removed from said table (due to the load
     209             :   // completing or being cancelled).
     210             :   bool                       mIsLoading : 1;
     211             : 
     212             :   // mIsCancelled is set to true when a sheet load is stopped by
     213             :   // Stop() or StopLoadingSheet() (which was removed in Bug 556446).
     214             :   // SheetLoadData::OnStreamComplete() checks this to avoid parsing
     215             :   // sheets that have been cancelled and such.
     216             :   bool                       mIsCancelled : 1;
     217             : 
     218             :   // mMustNotify is true if the load data is being loaded async and
     219             :   // the original function call that started the load has returned.
     220             :   // This applies only to observer notifications; load/error events
     221             :   // are fired for any SheetLoadData that has a non-null
     222             :   // mOwningElement.
     223             :   bool                       mMustNotify : 1;
     224             : 
     225             :   // mWasAlternate is true if the sheet was an alternate when the load data was
     226             :   // created.
     227             :   bool                       mWasAlternate : 1;
     228             : 
     229             :   // mUseSystemPrincipal is true if the system principal should be used for
     230             :   // this sheet, no matter what the channel principal is.  Only true for sync
     231             :   // loads.
     232             :   bool                       mUseSystemPrincipal : 1;
     233             : 
     234             :   // If true, this SheetLoadData is being used as a way to handle
     235             :   // async observer notification for an already-complete sheet.
     236             :   bool                       mSheetAlreadyComplete : 1;
     237             : 
     238             :   // This is the element that imported the sheet.  Needed to get the
     239             :   // charset set on it and to fire load/error events.
     240             :   nsCOMPtr<nsIStyleSheetLinkingElement> mOwningElement;
     241             : 
     242             :   // The observer that wishes to be notified of load completion
     243             :   nsCOMPtr<nsICSSLoaderObserver>        mObserver;
     244             : 
     245             :   // The principal that identifies who started loading us.
     246             :   nsCOMPtr<nsIPrincipal>                mLoaderPrincipal;
     247             : 
     248             :   // The node that identifies who started loading us.
     249             :   nsCOMPtr<nsINode>                     mRequestingNode;
     250             : 
     251             :   // The charset to use if the transport and sheet don't indicate one.
     252             :   // May be empty.  Must be empty if mOwningElement is non-null.
     253             :   nsCString                             mCharsetHint;
     254             : 
     255             :   // The status our load ended up with; this determines whether we
     256             :   // should fire error events or load events.  This gets initialized
     257             :   // by ScheduleLoadEventIfNeeded, and is only used after that has
     258             :   // been called.
     259             :   MOZ_INIT_OUTSIDE_CTOR nsresult        mStatus;
     260             : 
     261             : private:
     262             :   void FireLoadEvent(nsIThreadInternal* aThread);
     263             : };
     264             : 
     265             : #include "mozilla/Logging.h"
     266             : 
     267             : static mozilla::LazyLogModule sCssLoaderLog("nsCSSLoader");
     268             : 
     269             : static mozilla::LazyLogModule gSriPRLog("SRI");
     270             : 
     271             : #define LOG_ERROR(args) MOZ_LOG(sCssLoaderLog, mozilla::LogLevel::Error, args)
     272             : #define LOG_WARN(args) MOZ_LOG(sCssLoaderLog, mozilla::LogLevel::Warning, args)
     273             : #define LOG_DEBUG(args) MOZ_LOG(sCssLoaderLog, mozilla::LogLevel::Debug, args)
     274             : #define LOG(args) LOG_DEBUG(args)
     275             : 
     276             : #define LOG_ERROR_ENABLED() MOZ_LOG_TEST(sCssLoaderLog, mozilla::LogLevel::Error)
     277             : #define LOG_WARN_ENABLED() MOZ_LOG_TEST(sCssLoaderLog, mozilla::LogLevel::Warning)
     278             : #define LOG_DEBUG_ENABLED() MOZ_LOG_TEST(sCssLoaderLog, mozilla::LogLevel::Debug)
     279             : #define LOG_ENABLED() LOG_DEBUG_ENABLED()
     280             : 
     281             : #define LOG_URI(format, uri)                        \
     282             :   PR_BEGIN_MACRO                                    \
     283             :     NS_ASSERTION(uri, "Logging null uri");          \
     284             :     if (LOG_ENABLED()) {                            \
     285             :       LOG((format, uri->GetSpecOrDefault().get())); \
     286             :     }                                               \
     287             :   PR_END_MACRO
     288             : 
     289             : // And some convenience strings...
     290             : static const char* const gStateStrings[] = {
     291             :   "eSheetStateUnknown",
     292             :   "eSheetNeedsParser",
     293             :   "eSheetPending",
     294             :   "eSheetLoading",
     295             :   "eSheetComplete"
     296             : };
     297             : 
     298             : /********************************
     299             :  * SheetLoadData implementation *
     300             :  ********************************/
     301         498 : NS_IMPL_ISUPPORTS(SheetLoadData, nsIUnicharStreamLoaderObserver, nsIRunnable,
     302             :                   nsIThreadObserver)
     303             : 
     304          11 : SheetLoadData::SheetLoadData(Loader* aLoader,
     305             :                              const nsAString& aTitle,
     306             :                              nsIURI* aURI,
     307             :                              StyleSheet* aSheet,
     308             :                              nsIStyleSheetLinkingElement* aOwningElement,
     309             :                              bool aIsAlternate,
     310             :                              nsICSSLoaderObserver* aObserver,
     311             :                              nsIPrincipal* aLoaderPrincipal,
     312          11 :                              nsINode* aRequestingNode)
     313             :   : mLoader(aLoader),
     314             :     mTitle(aTitle),
     315             :     mURI(aURI),
     316             :     mLineNumber(1),
     317             :     mSheet(aSheet),
     318             :     mNext(nullptr),
     319             :     mPendingChildren(0),
     320             :     mSyncLoad(false),
     321             :     mIsNonDocumentSheet(false),
     322             :     mIsLoading(false),
     323             :     mIsCancelled(false),
     324             :     mMustNotify(false),
     325             :     mWasAlternate(aIsAlternate),
     326             :     mUseSystemPrincipal(false),
     327             :     mSheetAlreadyComplete(false),
     328             :     mOwningElement(aOwningElement),
     329             :     mObserver(aObserver),
     330             :     mLoaderPrincipal(aLoaderPrincipal),
     331          11 :     mRequestingNode(aRequestingNode)
     332             : {
     333          11 :   NS_PRECONDITION(mLoader, "Must have a loader!");
     334          11 : }
     335             : 
     336           3 : SheetLoadData::SheetLoadData(Loader* aLoader,
     337             :                              nsIURI* aURI,
     338             :                              StyleSheet* aSheet,
     339             :                              SheetLoadData* aParentData,
     340             :                              nsICSSLoaderObserver* aObserver,
     341             :                              nsIPrincipal* aLoaderPrincipal,
     342           3 :                              nsINode* aRequestingNode)
     343             :   : mLoader(aLoader),
     344             :     mURI(aURI),
     345             :     mLineNumber(1),
     346             :     mSheet(aSheet),
     347             :     mNext(nullptr),
     348             :     mParentData(aParentData),
     349             :     mPendingChildren(0),
     350             :     mSyncLoad(false),
     351             :     mIsNonDocumentSheet(false),
     352             :     mIsLoading(false),
     353             :     mIsCancelled(false),
     354             :     mMustNotify(false),
     355             :     mWasAlternate(false),
     356             :     mUseSystemPrincipal(false),
     357             :     mSheetAlreadyComplete(false),
     358             :     mOwningElement(nullptr),
     359             :     mObserver(aObserver),
     360             :     mLoaderPrincipal(aLoaderPrincipal),
     361           3 :     mRequestingNode(aRequestingNode)
     362             : {
     363           3 :   NS_PRECONDITION(mLoader, "Must have a loader!");
     364           3 :   if (mParentData) {
     365           3 :     mSyncLoad = mParentData->mSyncLoad;
     366           3 :     mIsNonDocumentSheet = mParentData->mIsNonDocumentSheet;
     367           3 :     mUseSystemPrincipal = mParentData->mUseSystemPrincipal;
     368           3 :     ++(mParentData->mPendingChildren);
     369             :   }
     370             : 
     371           3 :   NS_POSTCONDITION(!mUseSystemPrincipal || mSyncLoad,
     372             :                    "Shouldn't use system principal for async loads");
     373           3 : }
     374             : 
     375          44 : SheetLoadData::SheetLoadData(Loader* aLoader,
     376             :                              nsIURI* aURI,
     377             :                              StyleSheet* aSheet,
     378             :                              bool aSyncLoad,
     379             :                              bool aUseSystemPrincipal,
     380             :                              const nsCString& aCharset,
     381             :                              nsICSSLoaderObserver* aObserver,
     382             :                              nsIPrincipal* aLoaderPrincipal,
     383          44 :                              nsINode* aRequestingNode)
     384             :   : mLoader(aLoader),
     385             :     mURI(aURI),
     386             :     mLineNumber(1),
     387             :     mSheet(aSheet),
     388             :     mNext(nullptr),
     389             :     mPendingChildren(0),
     390             :     mSyncLoad(aSyncLoad),
     391             :     mIsNonDocumentSheet(true),
     392             :     mIsLoading(false),
     393             :     mIsCancelled(false),
     394             :     mMustNotify(false),
     395             :     mWasAlternate(false),
     396             :     mUseSystemPrincipal(aUseSystemPrincipal),
     397             :     mSheetAlreadyComplete(false),
     398             :     mOwningElement(nullptr),
     399             :     mObserver(aObserver),
     400             :     mLoaderPrincipal(aLoaderPrincipal),
     401             :     mRequestingNode(aRequestingNode),
     402          44 :     mCharsetHint(aCharset)
     403             : {
     404          44 :   NS_PRECONDITION(mLoader, "Must have a loader!");
     405          44 :   NS_POSTCONDITION(!mUseSystemPrincipal || mSyncLoad,
     406             :                    "Shouldn't use system principal for async loads");
     407          44 : }
     408             : 
     409         174 : SheetLoadData::~SheetLoadData()
     410             : {
     411          58 :   NS_CSS_NS_RELEASE_LIST_MEMBER(SheetLoadData, this, mNext);
     412         174 : }
     413             : 
     414             : NS_IMETHODIMP
     415           0 : SheetLoadData::Run()
     416             : {
     417           0 :   mLoader->HandleLoadEvent(this);
     418           0 :   return NS_OK;
     419             : }
     420             : 
     421             : NS_IMETHODIMP
     422           0 : SheetLoadData::OnDispatchedEvent(nsIThreadInternal* aThread)
     423             : {
     424           0 :   return NS_OK;
     425             : }
     426             : 
     427             : NS_IMETHODIMP
     428           0 : SheetLoadData::OnProcessNextEvent(nsIThreadInternal* aThread,
     429             :                                   bool aMayWait)
     430             : {
     431             :   // XXXkhuey this is insane!
     432             :   // We want to fire our load even before or after event processing,
     433             :   // whichever comes first.
     434           0 :   FireLoadEvent(aThread);
     435           0 :   return NS_OK;
     436             : }
     437             : 
     438             : NS_IMETHODIMP
     439          11 : SheetLoadData::AfterProcessNextEvent(nsIThreadInternal* aThread,
     440             :                                      bool aEventWasProcessed)
     441             : {
     442             :   // XXXkhuey this too!
     443             :   // We want to fire our load even before or after event processing,
     444             :   // whichever comes first.
     445          11 :   FireLoadEvent(aThread);
     446          11 :   return NS_OK;
     447             : }
     448             : 
     449             : void
     450          11 : SheetLoadData::FireLoadEvent(nsIThreadInternal* aThread)
     451             : {
     452             : 
     453             :   // First remove ourselves as a thread observer.  But we need to keep
     454             :   // ourselves alive while doing that!
     455          22 :   RefPtr<SheetLoadData> kungFuDeathGrip(this);
     456          11 :   aThread->RemoveObserver(this);
     457             : 
     458             :   // Now fire the event
     459          22 :   nsCOMPtr<nsINode> node = do_QueryInterface(mOwningElement);
     460          11 :   NS_ASSERTION(node, "How did that happen???");
     461             : 
     462          22 :   nsContentUtils::DispatchTrustedEvent(node->OwnerDoc(),
     463             :                                        node,
     464          11 :                                        NS_SUCCEEDED(mStatus) ?
     465          33 :                                          NS_LITERAL_STRING("load") :
     466          11 :                                          NS_LITERAL_STRING("error"),
     467          44 :                                        false, false);
     468             : 
     469             :   // And unblock onload
     470          11 :   if (mLoader->mDocument) {
     471          11 :     mLoader->mDocument->UnblockOnload(true);
     472             :   }
     473          11 : }
     474             : 
     475             : void
     476          58 : SheetLoadData::ScheduleLoadEventIfNeeded(nsresult aStatus)
     477             : {
     478          58 :   if (!mOwningElement) {
     479          47 :     return;
     480             :   }
     481             : 
     482          11 :   mStatus = aStatus;
     483             : 
     484          22 :   nsCOMPtr<nsIThread> thread = do_GetMainThread();
     485          22 :   nsCOMPtr<nsIThreadInternal> internalThread = do_QueryInterface(thread);
     486          11 :   if (NS_SUCCEEDED(internalThread->AddObserver(this))) {
     487             :     // Make sure to block onload here
     488          11 :     if (mLoader->mDocument) {
     489          11 :       mLoader->mDocument->BlockOnload();
     490             :     }
     491             :   }
     492             : }
     493             : 
     494             : /*********************
     495             :  * Style sheet reuse *
     496             :  *********************/
     497             : 
     498             : bool
     499           0 : LoaderReusableStyleSheets::FindReusableStyleSheet(nsIURI* aURL,
     500             :                                                   RefPtr<StyleSheet>& aResult)
     501             : {
     502           0 :   MOZ_ASSERT(aURL);
     503           0 :   for (size_t i = mReusableSheets.Length(); i > 0; --i) {
     504           0 :     size_t index = i - 1;
     505             :     bool sameURI;
     506           0 :     MOZ_ASSERT(mReusableSheets[index]->GetOriginalURI());
     507           0 :     nsresult rv = aURL->Equals(mReusableSheets[index]->GetOriginalURI(),
     508           0 :                                &sameURI);
     509           0 :     if (!NS_FAILED(rv) && sameURI) {
     510           0 :       aResult = mReusableSheets[index];
     511           0 :       mReusableSheets.RemoveElementAt(index);
     512           0 :       return true;
     513             :     }
     514             :   }
     515           0 :   return false;
     516             : }
     517             : 
     518             : /*************************
     519             :  * Loader Implementation *
     520             :  *************************/
     521             : 
     522           8 : Loader::Loader(StyleBackendType aType, DocGroup* aDocGroup)
     523             :   : mDocument(nullptr)
     524             :   , mDocGroup(aDocGroup)
     525             :   , mDatasToNotifyOn(0)
     526             :   , mCompatMode(eCompatibility_FullStandards)
     527             :   , mStyleBackendType(Some(aType))
     528             :   , mEnabled(true)
     529           8 :   , mReporter(new ConsoleReportCollector())
     530             : #ifdef DEBUG
     531          16 :   , mSyncCallback(false)
     532             : #endif
     533             : {
     534           8 : }
     535             : 
     536          55 : Loader::Loader(nsIDocument* aDocument)
     537             :   : mDocument(aDocument)
     538             :   , mDatasToNotifyOn(0)
     539             :   , mCompatMode(eCompatibility_FullStandards)
     540             :   , mEnabled(true)
     541          55 :   , mReporter(new ConsoleReportCollector())
     542             : #ifdef DEBUG
     543         110 :   , mSyncCallback(false)
     544             : #endif
     545             : {
     546          55 :   MOZ_ASSERT(mDocument, "We should get a valid document from the caller!");
     547             : 
     548             :   // We can just use the preferred set, since there are no sheets in the
     549             :   // document yet (if there are, how did they get there? _we_ load the sheets!)
     550             :   // and hence the selected set makes no sense at this time.
     551         110 :   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
     552          55 :   if (domDoc) {
     553          55 :     domDoc->GetPreferredStyleSheetSet(mPreferredSheet);
     554             :   }
     555          55 : }
     556             : 
     557           6 : Loader::~Loader()
     558             : {
     559           3 :   NS_ASSERTION(!mSheets || mSheets->mLoadingDatas.Count() == 0,
     560             :                "How did we get destroyed when there are loading data?");
     561           3 :   NS_ASSERTION(!mSheets || mSheets->mPendingDatas.Count() == 0,
     562             :                "How did we get destroyed when there are pending data?");
     563             :   // Note: no real need to revoke our stylesheet loaded events -- they
     564             :   // hold strong references to us, so if we're going away that means
     565             :   // they're all done.
     566           3 : }
     567             : 
     568             : void
     569           0 : Loader::DropDocumentReference(void)
     570             : {
     571           0 :   mDocument = nullptr;
     572             :   // Flush out pending datas just so we don't leak by accident.  These
     573             :   // loads should short-circuit through the mDocument check in
     574             :   // LoadSheet and just end up in SheetComplete immediately
     575           0 :   if (mSheets) {
     576           0 :     StartAlternateLoads();
     577             :   }
     578           0 : }
     579             : 
     580             : nsresult
     581           0 : Loader::SetPreferredSheet(const nsAString& aTitle)
     582             : {
     583             : #ifdef DEBUG
     584           0 :   nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(mDocument);
     585           0 :   if (doc) {
     586           0 :     nsAutoString currentPreferred;
     587           0 :     doc->GetLastStyleSheetSet(currentPreferred);
     588           0 :     if (DOMStringIsNull(currentPreferred)) {
     589           0 :       doc->GetPreferredStyleSheetSet(currentPreferred);
     590             :     }
     591           0 :     NS_ASSERTION(currentPreferred.Equals(aTitle),
     592             :                  "Unexpected argument to SetPreferredSheet");
     593             :   }
     594             : #endif
     595             : 
     596           0 :   mPreferredSheet = aTitle;
     597             : 
     598             :   // start any pending alternates that aren't alternates anymore
     599           0 :   if (mSheets) {
     600           0 :     LoadDataArray arr(mSheets->mPendingDatas.Count());
     601           0 :     for (auto iter = mSheets->mPendingDatas.Iter(); !iter.Done(); iter.Next()) {
     602           0 :       SheetLoadData* data = iter.Data();
     603           0 :       MOZ_ASSERT(data, "Must have a data");
     604             : 
     605             :       // Note that we don't want to affect what the selected style set is, so
     606             :       // use true for aHasAlternateRel.
     607           0 :       if (!data->mLoader->IsAlternate(data->mTitle, true)) {
     608           0 :         arr.AppendElement(data);
     609           0 :         iter.Remove();
     610             :       }
     611             :     }
     612             : 
     613           0 :     mDatasToNotifyOn += arr.Length();
     614           0 :     for (uint32_t i = 0; i < arr.Length(); ++i) {
     615           0 :       --mDatasToNotifyOn;
     616           0 :       LoadSheet(arr[i], eSheetNeedsParser, false);
     617             :     }
     618             :   }
     619             : 
     620           0 :   return NS_OK;
     621             : }
     622             : 
     623             : static const char kCharsetSym[] = "@charset \"";
     624             : 
     625           0 : static bool GetCharsetFromData(const char* aStyleSheetData,
     626             :                                uint32_t aDataLength,
     627             :                                nsACString& aCharset)
     628             : {
     629           0 :   aCharset.Truncate();
     630           0 :   if (aDataLength <= sizeof(kCharsetSym) - 1)
     631           0 :     return false;
     632             : 
     633           0 :   if (strncmp(aStyleSheetData,
     634             :               kCharsetSym,
     635             :               sizeof(kCharsetSym) - 1)) {
     636           0 :     return false;
     637             :   }
     638             : 
     639           0 :   for (uint32_t i = sizeof(kCharsetSym) - 1; i < aDataLength; ++i) {
     640           0 :     char c = aStyleSheetData[i];
     641           0 :     if (c == '"') {
     642           0 :       ++i;
     643           0 :       if (i < aDataLength && aStyleSheetData[i] == ';') {
     644           0 :         return true;
     645             :       }
     646             :       // fail
     647           0 :       break;
     648             :     }
     649           0 :     aCharset.Append(c);
     650             :   }
     651             : 
     652             :   // Did not see end quote or semicolon
     653           0 :   aCharset.Truncate();
     654           0 :   return false;
     655             : }
     656             : 
     657             : NS_IMETHODIMP
     658          53 : SheetLoadData::OnDetermineCharset(nsIUnicharStreamLoader* aLoader,
     659             :                                   nsISupports* aContext,
     660             :                                   nsACString const& aSegment,
     661             :                                   nsACString& aCharset)
     662             : {
     663          53 :   NS_PRECONDITION(!mOwningElement || mCharsetHint.IsEmpty(),
     664             :                   "Can't have element _and_ charset hint");
     665             : 
     666          53 :   LOG_URI("SheetLoadData::OnDetermineCharset for '%s'", mURI);
     667             : 
     668             :   // The precedence is (per CSS3 Syntax 2012-11-08 ED):
     669             :   // BOM
     670             :   // Channel
     671             :   // @charset rule
     672             :   // charset attribute on the referrer
     673             :   // encoding of the referrer
     674             :   // UTF-8
     675             : 
     676          53 :   aCharset.Truncate();
     677             : 
     678             :   const Encoding* encoding;
     679             :   size_t bomLength;
     680          53 :   Tie(encoding, bomLength) = Encoding::ForBOM(aSegment);
     681             :   Unused << bomLength;
     682          53 :   if (encoding) {
     683           0 :     encoding->Name(aCharset);
     684             :     // aCharset is now either "UTF-16BE", "UTF-16BE" or "UTF-8"
     685             :     // which will swallow the BOM.
     686           0 :     mCharset.Assign(aCharset);
     687           0 :     LOG(("  Setting from BOM to: %s", PromiseFlatCString(aCharset).get()));
     688           0 :     return NS_OK;
     689             :   }
     690             : 
     691         106 :   nsCOMPtr<nsIChannel> channel;
     692         106 :   nsAutoCString specified;
     693          53 :   aLoader->GetChannel(getter_AddRefs(channel));
     694          53 :   if (channel) {
     695          53 :     channel->GetContentCharset(specified);
     696          53 :     encoding = Encoding::ForLabel(specified);
     697          53 :     if (encoding) {
     698          53 :       encoding->Name(aCharset);
     699          53 :       mCharset.Assign(aCharset);
     700          53 :       LOG(("  Setting from HTTP to: %s", PromiseFlatCString(aCharset).get()));
     701          53 :       return NS_OK;
     702             :     }
     703             :   }
     704             : 
     705           0 :   if (GetCharsetFromData(aSegment.BeginReading(),
     706             :                          aSegment.Length(),
     707             :                          specified)) {
     708           0 :     encoding = Encoding::ForLabel(specified);
     709           0 :     if (encoding) {
     710           0 :       encoding->Name(aCharset);
     711           0 :       if (encoding == UTF_16BE_ENCODING ||
     712           0 :           encoding == UTF_16LE_ENCODING) {
     713             :         // Be consistent with HTML <meta> handling in face of impossibility.
     714             :         // When the @charset rule itself evidently was not UTF-16-encoded,
     715             :         // it saying UTF-16 has to be a lie.
     716           0 :         aCharset.AssignLiteral("UTF-8");
     717             :       }
     718           0 :       mCharset.Assign(aCharset);
     719           0 :       LOG(("  Setting from @charset rule to: %s",
     720             :           PromiseFlatCString(aCharset).get()));
     721           0 :       return NS_OK;
     722             :     }
     723             :   }
     724             : 
     725             :   // Now try the charset on the <link> or processing instruction
     726             :   // that loaded us
     727           0 :   if (mOwningElement) {
     728           0 :     nsAutoString specified16;
     729           0 :     mOwningElement->GetCharset(specified16);
     730           0 :     encoding = Encoding::ForLabel(specified16);
     731           0 :     if (encoding) {
     732           0 :       encoding->Name(aCharset);
     733           0 :       mCharset.Assign(aCharset);
     734           0 :       LOG(("  Setting from charset attribute to: %s",
     735             :           PromiseFlatCString(aCharset).get()));
     736           0 :       return NS_OK;
     737             :     }
     738             :   }
     739             : 
     740             :   // In the preload case, the value of the charset attribute on <link> comes
     741             :   // in via mCharsetHint instead.
     742           0 :   encoding = Encoding::ForLabel(mCharsetHint);
     743           0 :   if (encoding) {
     744           0 :     encoding->Name(aCharset);
     745           0 :     mCharset.Assign(aCharset);
     746           0 :       LOG(("  Setting from charset attribute (preload case) to: %s",
     747             :           PromiseFlatCString(aCharset).get()));
     748           0 :     return NS_OK;
     749             :   }
     750             : 
     751             :   // Try charset from the parent stylesheet.
     752           0 :   if (mParentData) {
     753           0 :     aCharset = mParentData->mCharset;
     754           0 :     if (!aCharset.IsEmpty()) {
     755           0 :       mCharset.Assign(aCharset);
     756           0 :       LOG(("  Setting from parent sheet to: %s",
     757             :           PromiseFlatCString(aCharset).get()));
     758           0 :       return NS_OK;
     759             :     }
     760             :   }
     761             : 
     762           0 :   if (mLoader->mDocument) {
     763             :     // no useful data on charset.  Try the document charset.
     764           0 :     auto encoding = mLoader->mDocument->GetDocumentCharacterSet();
     765           0 :     encoding->Name(aCharset);
     766           0 :     mCharset.Assign(aCharset);
     767           0 :     LOG(("  Setting from document to: %s", PromiseFlatCString(aCharset).get()));
     768           0 :     return NS_OK;
     769             :   }
     770             : 
     771           0 :   aCharset.AssignLiteral("UTF-8");
     772           0 :   mCharset = aCharset;
     773           0 :   LOG(("  Setting from default to: %s", PromiseFlatCString(aCharset).get()));
     774           0 :   return NS_OK;
     775             : }
     776             : 
     777             : already_AddRefed<nsIURI>
     778           0 : SheetLoadData::GetReferrerURI()
     779             : {
     780           0 :   nsCOMPtr<nsIURI> uri;
     781           0 :   if (mParentData)
     782           0 :     uri = mParentData->mSheet->GetSheetURI();
     783           0 :   if (!uri && mLoader->mDocument)
     784           0 :     uri = mLoader->mDocument->GetDocumentURI();
     785           0 :   return uri.forget();
     786             : }
     787             : 
     788             : /*
     789             :  * Here we need to check that the load did not give us an http error
     790             :  * page and check the mimetype on the channel to make sure we're not
     791             :  * loading non-text/css data in standards mode.
     792             :  */
     793             : NS_IMETHODIMP
     794          53 : SheetLoadData::OnStreamComplete(nsIUnicharStreamLoader* aLoader,
     795             :                                 nsISupports* aContext,
     796             :                                 nsresult aStatus,
     797             :                                 const nsAString& aBuffer)
     798             : {
     799          53 :   LOG(("SheetLoadData::OnStreamComplete"));
     800          53 :   NS_ASSERTION(!mLoader->mSyncCallback, "Synchronous callback from necko");
     801             : 
     802          53 :   if (mIsCancelled) {
     803             :     // Just return.  Don't call SheetComplete -- it's already been
     804             :     // called and calling it again will lead to an extra NS_RELEASE on
     805             :     // this data and a likely crash.
     806           0 :     return NS_OK;
     807             :   }
     808             : 
     809          53 :   if (!mLoader->mDocument && !mIsNonDocumentSheet) {
     810             :     // Sorry, we don't care about this load anymore
     811           0 :     LOG_WARN(("  No document and not non-document sheet; dropping load"));
     812           0 :     mLoader->SheetComplete(this, NS_BINDING_ABORTED);
     813           0 :     return NS_OK;
     814             :   }
     815             : 
     816          53 :   if (NS_FAILED(aStatus)) {
     817           0 :     LOG_WARN(("  Load failed: status 0x%" PRIx32, static_cast<uint32_t>(aStatus)));
     818             :     // Handle sheet not loading error because source was a tracking URL.
     819             :     // We make a note of this sheet node by including it in a dedicated
     820             :     // array of blocked tracking nodes under its parent document.
     821             :     //
     822             :     // Multiple sheet load instances might be tied to this request,
     823             :     // we annotate each one linked to a valid owning element (node).
     824           0 :     if (aStatus == NS_ERROR_TRACKING_URI) {
     825           0 :       nsIDocument* doc = mLoader->GetDocument();
     826           0 :       if (doc) {
     827           0 :         for (SheetLoadData* data = this; data; data = data->mNext) {
     828             :           // mOwningElement may be null but AddBlockTrackingNode can cope
     829           0 :           nsCOMPtr<nsIContent> content = do_QueryInterface(data->mOwningElement);
     830           0 :           doc->AddBlockedTrackingNode(content);
     831             :         }
     832             :       }
     833             :     }
     834           0 :     mLoader->SheetComplete(this, aStatus);
     835           0 :     return NS_OK;
     836             :   }
     837             : 
     838         106 :   nsCOMPtr<nsIChannel> channel;
     839          53 :   nsresult result = aLoader->GetChannel(getter_AddRefs(channel));
     840          53 :   if (NS_FAILED(result)) {
     841           0 :     LOG_WARN(("  No channel from loader"));
     842           0 :     mLoader->SheetComplete(this, result);
     843           0 :     return NS_OK;
     844             :   }
     845             : 
     846         106 :   nsCOMPtr<nsIURI> originalURI;
     847          53 :   channel->GetOriginalURI(getter_AddRefs(originalURI));
     848             : 
     849             :   // If the channel's original URI is "chrome:", we want that, since
     850             :   // the observer code in nsXULPrototypeCache depends on chrome stylesheets
     851             :   // having a chrome URI.  (Whether or not chrome stylesheets come through
     852             :   // this codepath seems nondeterministic.)
     853             :   // Otherwise we want the potentially-HTTP-redirected URI.
     854         106 :   nsCOMPtr<nsIURI> channelURI;
     855          53 :   NS_GetFinalChannelURI(channel, getter_AddRefs(channelURI));
     856             : 
     857          53 :   if (!channelURI || !originalURI) {
     858           0 :     NS_ERROR("Someone just violated the nsIRequest contract");
     859           0 :     LOG_WARN(("  Channel without a URI.  Bad!"));
     860           0 :     mLoader->SheetComplete(this, NS_ERROR_UNEXPECTED);
     861           0 :     return NS_OK;
     862             :   }
     863             : 
     864         106 :   nsCOMPtr<nsIPrincipal> principal;
     865          53 :   nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
     866          53 :   result = NS_ERROR_NOT_AVAILABLE;
     867          53 :   if (secMan) {  // Could be null if we already shut down
     868          53 :     if (mUseSystemPrincipal) {
     869          26 :       result = secMan->GetSystemPrincipal(getter_AddRefs(principal));
     870             :     } else {
     871          27 :       result = secMan->GetChannelResultPrincipal(channel, getter_AddRefs(principal));
     872             :     }
     873             :   }
     874             : 
     875          53 :   if (NS_FAILED(result)) {
     876           0 :     LOG_WARN(("  Couldn't get principal"));
     877           0 :     mLoader->SheetComplete(this, result);
     878           0 :     return NS_OK;
     879             :   }
     880             : 
     881          53 :   mSheet->SetPrincipal(principal);
     882             : 
     883             :   // If it's an HTTP channel, we want to make sure this is not an
     884             :   // error document we got.
     885         106 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
     886          53 :   if (httpChannel) {
     887             :     bool requestSucceeded;
     888           0 :     result = httpChannel->GetRequestSucceeded(&requestSucceeded);
     889           0 :     if (NS_SUCCEEDED(result) && !requestSucceeded) {
     890           0 :       LOG(("  Load returned an error page"));
     891           0 :       mLoader->SheetComplete(this, NS_ERROR_NOT_AVAILABLE);
     892           0 :       return NS_OK;
     893             :     }
     894             : 
     895           0 :     nsAutoCString sourceMapURL;
     896           0 :     if (nsContentUtils::GetSourceMapURL(httpChannel, sourceMapURL)) {
     897           0 :       mSheet->SetSourceMapURL(NS_ConvertUTF8toUTF16(sourceMapURL));
     898             :     }
     899             :   }
     900             : 
     901         106 :   nsAutoCString contentType;
     902          53 :   if (channel) {
     903          53 :     channel->GetContentType(contentType);
     904             :   }
     905             : 
     906             :   // In standards mode, a style sheet must have one of these MIME
     907             :   // types to be processed at all.  In quirks mode, we accept any
     908             :   // MIME type, but only if the style sheet is same-origin with the
     909             :   // requesting document or parent sheet.  See bug 524223.
     910             : 
     911          53 :   bool validType = contentType.EqualsLiteral("text/css") ||
     912          53 :     contentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE) ||
     913          53 :     contentType.IsEmpty();
     914             : 
     915          53 :   if (!validType) {
     916             :     const char *errorMessage;
     917             :     uint32_t errorFlag;
     918           0 :     bool sameOrigin = true;
     919             : 
     920           0 :     if (mLoaderPrincipal) {
     921             :       bool subsumed;
     922           0 :       result = mLoaderPrincipal->Subsumes(principal, &subsumed);
     923           0 :       if (NS_FAILED(result) || !subsumed) {
     924           0 :         sameOrigin = false;
     925             :       }
     926             :     }
     927             : 
     928           0 :     if (sameOrigin && mLoader->mCompatMode == eCompatibility_NavQuirks) {
     929           0 :       errorMessage = "MimeNotCssWarn";
     930           0 :       errorFlag = nsIScriptError::warningFlag;
     931             :     } else {
     932           0 :       errorMessage = "MimeNotCss";
     933           0 :       errorFlag = nsIScriptError::errorFlag;
     934             :     }
     935             : 
     936             :     const nsString& specUTF16 =
     937           0 :       NS_ConvertUTF8toUTF16(channelURI->GetSpecOrDefault());
     938           0 :     const nsString& ctypeUTF16 = NS_ConvertASCIItoUTF16(contentType);
     939           0 :     const char16_t *strings[] = { specUTF16.get(), ctypeUTF16.get() };
     940             : 
     941           0 :     nsCOMPtr<nsIURI> referrer = GetReferrerURI();
     942           0 :     nsContentUtils::ReportToConsole(errorFlag,
     943           0 :                                     NS_LITERAL_CSTRING("CSS Loader"),
     944           0 :                                     mLoader->mDocument,
     945             :                                     nsContentUtils::eCSS_PROPERTIES,
     946             :                                     errorMessage,
     947           0 :                                     strings, ArrayLength(strings),
     948           0 :                                     referrer);
     949             : 
     950           0 :     if (errorFlag == nsIScriptError::errorFlag) {
     951           0 :       LOG_WARN(("  Ignoring sheet with improper MIME type %s",
     952             :                 contentType.get()));
     953           0 :       mLoader->SheetComplete(this, NS_ERROR_NOT_AVAILABLE);
     954           0 :       return NS_OK;
     955             :     }
     956             :   }
     957             : 
     958         106 :   SRIMetadata sriMetadata;
     959          53 :   mSheet->GetIntegrity(sriMetadata);
     960          53 :   if (sriMetadata.IsEmpty()) {
     961         106 :     nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
     962          53 :     if (loadInfo && loadInfo->GetEnforceSRI()) {
     963           0 :       LOG(("  Load was blocked by SRI"));
     964           0 :       MOZ_LOG(gSriPRLog, mozilla::LogLevel::Debug,
     965             :               ("css::Loader::OnStreamComplete, required SRI not found"));
     966           0 :       mLoader->SheetComplete(this, NS_ERROR_SRI_CORRUPT);
     967             :       // log the failed load to web console
     968           0 :       nsCOMPtr<nsIContentSecurityPolicy> csp;
     969           0 :       loadInfo->LoadingPrincipal()->GetCsp(getter_AddRefs(csp));
     970           0 :       nsAutoCString spec;
     971           0 :       mLoader->mDocument->GetDocumentURI()->GetAsciiSpec(spec);
     972             :       // line number unknown. mRequestingNode doesn't bear this info.
     973           0 :       csp->LogViolationDetails(
     974             :         nsIContentSecurityPolicy::VIOLATION_TYPE_REQUIRE_SRI_FOR_STYLE,
     975           0 :         NS_ConvertUTF8toUTF16(spec), EmptyString(),
     976           0 :         0, EmptyString(), EmptyString());
     977           0 :       return NS_OK;
     978             :     }
     979             :   } else {
     980           0 :     nsAutoCString sourceUri;
     981           0 :     if (mLoader->mDocument && mLoader->mDocument->GetDocumentURI()) {
     982           0 :       mLoader->mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
     983             :     }
     984           0 :     nsresult rv = SRICheck::VerifyIntegrity(sriMetadata, aLoader, aBuffer,
     985           0 :                                             sourceUri, mLoader->mReporter);
     986             : 
     987           0 :     nsCOMPtr<nsILoadGroup> loadGroup;
     988           0 :     channel->GetLoadGroup(getter_AddRefs(loadGroup));
     989           0 :     if (loadGroup) {
     990           0 :       mLoader->mReporter->FlushConsoleReports(loadGroup);
     991             :     } else {
     992           0 :       mLoader->mReporter->FlushConsoleReports(mLoader->mDocument);
     993             :     }
     994             : 
     995           0 :     if (NS_FAILED(rv)) {
     996           0 :       LOG(("  Load was blocked by SRI"));
     997           0 :       MOZ_LOG(gSriPRLog, mozilla::LogLevel::Debug,
     998             :               ("css::Loader::OnStreamComplete, bad metadata"));
     999           0 :       mLoader->SheetComplete(this, NS_ERROR_SRI_CORRUPT);
    1000           0 :       return NS_OK;
    1001             :     }
    1002             :   }
    1003             : 
    1004             :   // Enough to set the URIs on mSheet, since any sibling datas we have share
    1005             :   // the same mInner as mSheet and will thus get the same URI.
    1006          53 :   mSheet->SetURIs(channelURI, originalURI, channelURI);
    1007             : 
    1008             :   bool completed;
    1009          53 :   result = mLoader->ParseSheet(aBuffer, this, completed);
    1010          53 :   NS_ASSERTION(completed || !mSyncLoad, "sync load did not complete");
    1011          53 :   return result;
    1012             : }
    1013             : 
    1014             : bool
    1015          73 : Loader::IsAlternate(const nsAString& aTitle, bool aHasAlternateRel)
    1016             : {
    1017             :   // A sheet is alternate if it has a nonempty title that doesn't match the
    1018             :   // currently selected style set.  But if there _is_ no currently selected
    1019             :   // style set, the sheet wasn't marked as an alternate explicitly, and aTitle
    1020             :   // is nonempty, we should select the style set corresponding to aTitle, since
    1021             :   // that's a preferred sheet.
    1022          73 :   if (aTitle.IsEmpty()) {
    1023          73 :     return false;
    1024             :   }
    1025             : 
    1026           0 :   if (!aHasAlternateRel && mDocument && mPreferredSheet.IsEmpty()) {
    1027             :     // There's no preferred set yet, and we now have a sheet with a title.
    1028             :     // Make that be the preferred set.
    1029           0 :     mDocument->SetHeaderData(nsGkAtoms::headerDefaultStyle, aTitle);
    1030             :     // We're definitely not an alternate
    1031           0 :     return false;
    1032             :   }
    1033             : 
    1034           0 :   return !aTitle.Equals(mPreferredSheet);
    1035             : }
    1036             : 
    1037             : nsresult
    1038           0 : Loader::ObsoleteSheet(nsIURI* aURI)
    1039             : {
    1040           0 :   if (!mSheets) {
    1041           0 :     return NS_OK;
    1042             :   }
    1043           0 :   if (!aURI) {
    1044           0 :     return NS_ERROR_INVALID_ARG;
    1045             :   }
    1046           0 :   for (auto iter = mSheets->mCompleteSheets.Iter(); !iter.Done(); iter.Next()) {
    1047           0 :     nsIURI* sheetURI = iter.Key()->GetURI();
    1048             :     bool areEqual;
    1049           0 :     nsresult rv = sheetURI->Equals(aURI, &areEqual);
    1050           0 :     if (NS_SUCCEEDED(rv) && areEqual) {
    1051           0 :       iter.Remove();
    1052             :     }
    1053             :   }
    1054           0 :   return NS_OK;
    1055             : }
    1056             : 
    1057             : nsresult
    1058          68 : Loader::CheckContentPolicy(nsIPrincipal* aSourcePrincipal,
    1059             :                           nsIURI* aTargetURI,
    1060             :                           nsISupports* aContext,
    1061             :                           bool aIsPreload)
    1062             : {
    1063             :   // When performing a system load (e.g. aUseSystemPrincipal = true)
    1064             :   // then aSourcePrincipal == null; don't consult content policies.
    1065          68 :   if (!aSourcePrincipal) {
    1066          59 :     return NS_OK;
    1067             :   }
    1068             : 
    1069             :   nsContentPolicyType contentPolicyType =
    1070           9 :     aIsPreload ? nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD
    1071           9 :                : nsIContentPolicy::TYPE_INTERNAL_STYLESHEET;
    1072             : 
    1073           9 :   int16_t shouldLoad = nsIContentPolicy::ACCEPT;
    1074          18 :   nsresult rv = NS_CheckContentLoadPolicy(contentPolicyType,
    1075             :                                           aTargetURI,
    1076             :                                           aSourcePrincipal,
    1077             :                                           aContext,
    1078          18 :                                           NS_LITERAL_CSTRING("text/css"),
    1079             :                                           nullptr,  //extra param
    1080             :                                           &shouldLoad,
    1081             :                                           nsContentUtils::GetContentPolicy(),
    1082          18 :                                           nsContentUtils::GetSecurityManager());
    1083           9 :    if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
    1084           0 :      return NS_ERROR_CONTENT_BLOCKED;
    1085             :    }
    1086           9 :    return NS_OK;
    1087             : }
    1088             : 
    1089             : /**
    1090             :  * CreateSheet() creates a CSSStyleSheet object for the given URI,
    1091             :  * if any.  If there is no URI given, we just create a new style sheet
    1092             :  * object.  Otherwise, we check for an existing style sheet object for
    1093             :  * that uri in various caches and clone it if we find it.  Cloned
    1094             :  * sheets will have the title/media/enabled state of the sheet they
    1095             :  * are clones off; make sure to call PrepareSheet() on the result of
    1096             :  * CreateSheet().
    1097             :  */
    1098             : nsresult
    1099          73 : Loader::CreateSheet(nsIURI* aURI,
    1100             :                     nsIContent* aLinkingContent,
    1101             :                     nsIPrincipal* aLoaderPrincipal,
    1102             :                     css::SheetParsingMode aParsingMode,
    1103             :                     CORSMode aCORSMode,
    1104             :                     ReferrerPolicy aReferrerPolicy,
    1105             :                     const nsAString& aIntegrity,
    1106             :                     bool aSyncLoad,
    1107             :                     bool aHasAlternateRel,
    1108             :                     const nsAString& aTitle,
    1109             :                     StyleSheetState& aSheetState,
    1110             :                     bool *aIsAlternate,
    1111             :                     RefPtr<StyleSheet>* aSheet)
    1112             : {
    1113          73 :   LOG(("css::Loader::CreateSheet"));
    1114          73 :   NS_PRECONDITION(aSheet, "Null out param!");
    1115             : 
    1116          73 :   if (!mSheets) {
    1117          28 :     mSheets = new Sheets();
    1118             :   }
    1119             : 
    1120          73 :   *aSheet = nullptr;
    1121          73 :   aSheetState = eSheetStateUnknown;
    1122             : 
    1123             :   // Check the alternate state before doing anything else, because it
    1124             :   // can mess with our hashtables.
    1125          73 :   *aIsAlternate = IsAlternate(aTitle, aHasAlternateRel);
    1126             : 
    1127          73 :   if (aURI) {
    1128          68 :     aSheetState = eSheetComplete;
    1129         136 :     RefPtr<StyleSheet> sheet;
    1130             : 
    1131             :     // First, the XUL cache
    1132             : #ifdef MOZ_XUL
    1133          68 :     if (IsChromeURI(aURI)) {
    1134          52 :       nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
    1135          52 :       if (cache && cache->IsEnabled()) {
    1136          52 :         sheet = cache->GetStyleSheet(aURI, GetStyleBackendType());
    1137          52 :         LOG(("  From XUL cache: %p", sheet.get()));
    1138             :       }
    1139             :     }
    1140             : #endif
    1141             : 
    1142          68 :     bool fromCompleteSheets = false;
    1143          68 :     if (!sheet) {
    1144             :       // Then our per-document complete sheets.
    1145         106 :       URIPrincipalReferrerPolicyAndCORSModeHashKey key(aURI, aLoaderPrincipal, aCORSMode, aReferrerPolicy);
    1146             : 
    1147          53 :       StyleSheet* completeSheet = nullptr;
    1148          53 :       mSheets->mCompleteSheets.Get(&key, &completeSheet);
    1149          53 :       sheet = completeSheet;
    1150          53 :       LOG(("  From completed: %p", sheet.get()));
    1151             : 
    1152          53 :       fromCompleteSheets = !!sheet;
    1153             :     }
    1154             : 
    1155          68 :     if (sheet) {
    1156             :       // This sheet came from the XUL cache or our per-document hashtable; it
    1157             :       // better be a complete sheet.
    1158          15 :       NS_ASSERTION(sheet->IsComplete(),
    1159             :                    "Sheet thinks it's not complete while we think it is");
    1160             : 
    1161             :       // Make sure it hasn't been modified; if it has, we can't use it
    1162          15 :       if (sheet->IsModified()) {
    1163           0 :         LOG(("  Not cloning completed sheet %p because it's been modified",
    1164             :              sheet.get()));
    1165           0 :         sheet = nullptr;
    1166           0 :         fromCompleteSheets = false;
    1167             :       }
    1168             :     }
    1169             : 
    1170             :     // Then loading sheets
    1171          68 :     if (!sheet && !aSyncLoad) {
    1172           8 :       aSheetState = eSheetLoading;
    1173           8 :       SheetLoadData* loadData = nullptr;
    1174          16 :       URIPrincipalReferrerPolicyAndCORSModeHashKey key(aURI, aLoaderPrincipal, aCORSMode, aReferrerPolicy);
    1175           8 :       mSheets->mLoadingDatas.Get(&key, &loadData);
    1176           8 :       if (loadData) {
    1177           0 :         sheet = loadData->mSheet;
    1178           0 :         LOG(("  From loading: %p", sheet.get()));
    1179             : 
    1180             : #ifdef DEBUG
    1181             :         bool debugEqual;
    1182           0 :         NS_ASSERTION((!aLoaderPrincipal && !loadData->mLoaderPrincipal) ||
    1183             :                      (aLoaderPrincipal && loadData->mLoaderPrincipal &&
    1184             :                       NS_SUCCEEDED(aLoaderPrincipal->
    1185             :                                    Equals(loadData->mLoaderPrincipal,
    1186             :                                           &debugEqual)) && debugEqual),
    1187             :                      "Principals should be the same");
    1188             : #endif
    1189             :       }
    1190             : 
    1191             :       // Then alternate sheets
    1192           8 :       if (!sheet) {
    1193           8 :         aSheetState = eSheetPending;
    1194           8 :         loadData = nullptr;
    1195           8 :         mSheets->mPendingDatas.Get(&key, &loadData);
    1196           8 :         if (loadData) {
    1197           0 :           sheet = loadData->mSheet;
    1198           0 :           LOG(("  From pending: %p", sheet.get()));
    1199             : 
    1200             : #ifdef DEBUG
    1201             :           bool debugEqual;
    1202           0 :           NS_ASSERTION((!aLoaderPrincipal && !loadData->mLoaderPrincipal) ||
    1203             :                        (aLoaderPrincipal && loadData->mLoaderPrincipal &&
    1204             :                         NS_SUCCEEDED(aLoaderPrincipal->
    1205             :                                      Equals(loadData->mLoaderPrincipal,
    1206             :                                             &debugEqual)) && debugEqual),
    1207             :                        "Principals should be the same");
    1208             : #endif
    1209             :         }
    1210             :       }
    1211             :     }
    1212             : 
    1213          68 :     if (sheet) {
    1214             :       // The sheet we have now should be either incomplete or unmodified
    1215          15 :       NS_ASSERTION(!sheet->IsModified() ||
    1216             :                    !sheet->IsComplete(),
    1217             :                    "Unexpected modified complete sheet");
    1218          15 :       NS_ASSERTION(sheet->IsComplete() ||
    1219             :                    aSheetState != eSheetComplete,
    1220             :                    "Sheet thinks it's not complete while we think it is");
    1221             : 
    1222             :       RefPtr<StyleSheet> clonedSheet =
    1223          30 :         sheet->Clone(nullptr, nullptr, nullptr, nullptr);
    1224          15 :       *aSheet = Move(clonedSheet);
    1225          45 :       if (*aSheet && fromCompleteSheets &&
    1226          15 :           !sheet->GetOwnerNode() &&
    1227           0 :           !sheet->GetParentSheet()) {
    1228             :         // The sheet we're cloning isn't actually referenced by
    1229             :         // anyone.  Replace it in the cache, so that if our CSSOM is
    1230             :         // later modified we don't end up with two copies of our inner
    1231             :         // hanging around.
    1232           0 :         URIPrincipalReferrerPolicyAndCORSModeHashKey key(aURI, aLoaderPrincipal, aCORSMode, aReferrerPolicy);
    1233           0 :         NS_ASSERTION((*aSheet)->IsComplete(),
    1234             :                      "Should only be caching complete sheets");
    1235           0 :         mSheets->mCompleteSheets.Put(&key, *aSheet);
    1236             :       }
    1237             :     }
    1238             :   }
    1239             : 
    1240          73 :   if (!*aSheet) {
    1241          58 :     aSheetState = eSheetNeedsParser;
    1242             :     nsIURI *sheetURI;
    1243         116 :     nsCOMPtr<nsIURI> baseURI;
    1244             :     nsIURI* originalURI;
    1245          58 :     if (!aURI) {
    1246             :       // Inline style.  Use the document's base URL so that @import in
    1247             :       // the inline sheet picks up the right base.
    1248           5 :       NS_ASSERTION(aLinkingContent, "Inline stylesheet without linking content?");
    1249           5 :       baseURI = aLinkingContent->GetBaseURI();
    1250           5 :       sheetURI = aLinkingContent->OwnerDoc()->GetDocumentURI();
    1251           5 :       originalURI = nullptr;
    1252             :     } else {
    1253          53 :       baseURI = aURI;
    1254          53 :       sheetURI = aURI;
    1255          53 :       originalURI = aURI;
    1256             :     }
    1257             : 
    1258         116 :     SRIMetadata sriMetadata;
    1259          58 :     if (!aIntegrity.IsEmpty()) {
    1260           0 :       MOZ_LOG(gSriPRLog, mozilla::LogLevel::Debug,
    1261             :               ("css::Loader::CreateSheet, integrity=%s",
    1262             :                NS_ConvertUTF16toUTF8(aIntegrity).get()));
    1263           0 :       nsAutoCString sourceUri;
    1264           0 :       if (mDocument && mDocument->GetDocumentURI()) {
    1265           0 :         mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
    1266             :       }
    1267           0 :       SRICheck::IntegrityMetadata(aIntegrity, sourceUri, mReporter,
    1268           0 :                                   &sriMetadata);
    1269             :     }
    1270             : 
    1271          58 :     if (GetStyleBackendType() == StyleBackendType::Gecko) {
    1272          58 :       *aSheet = new CSSStyleSheet(aParsingMode, aCORSMode, aReferrerPolicy, sriMetadata);
    1273             :     } else {
    1274           0 :       *aSheet = new ServoStyleSheet(aParsingMode, aCORSMode, aReferrerPolicy, sriMetadata);
    1275             :     }
    1276          58 :     (*aSheet)->SetURIs(sheetURI, originalURI, baseURI);
    1277             :   }
    1278             : 
    1279          73 :   NS_ASSERTION(*aSheet, "We should have a sheet by now!");
    1280          73 :   NS_ASSERTION(aSheetState != eSheetStateUnknown, "Have to set a state!");
    1281          73 :   LOG(("  State: %s", gStateStrings[aSheetState]));
    1282             : 
    1283          73 :   return NS_OK;
    1284             : }
    1285             : 
    1286             : /**
    1287             :  * PrepareSheet() handles setting the media and title on the sheet, as
    1288             :  * well as setting the enabled state based on the title and whether
    1289             :  * the sheet had "alternate" in its rel.
    1290             :  */
    1291             : void
    1292          73 : Loader::PrepareSheet(StyleSheet* aSheet,
    1293             :                      const nsAString& aTitle,
    1294             :                      const nsAString& aMediaString,
    1295             :                      MediaList* aMediaList,
    1296             :                      Element* aScopeElement,
    1297             :                      bool aIsAlternate)
    1298             : {
    1299          73 :   NS_PRECONDITION(aSheet, "Must have a sheet!");
    1300             : 
    1301         146 :   RefPtr<MediaList> mediaList(aMediaList);
    1302             : 
    1303          73 :   if (!aMediaString.IsEmpty()) {
    1304           0 :     NS_ASSERTION(!aMediaList,
    1305             :                  "must not provide both aMediaString and aMediaList");
    1306           0 :     mediaList = MediaList::Create(GetStyleBackendType(), aMediaString);
    1307             :   }
    1308             : 
    1309          73 :   aSheet->SetMedia(mediaList);
    1310             : 
    1311          73 :   aSheet->SetTitle(aTitle);
    1312          73 :   aSheet->SetEnabled(!aIsAlternate);
    1313             : 
    1314          73 :   if (aSheet->IsGecko()) {
    1315          73 :     aSheet->AsGecko()->SetScopeElement(aScopeElement);
    1316             :   } else {
    1317           0 :     if (aScopeElement) {
    1318           0 :       NS_WARNING("stylo: scoped style sheets not supported");
    1319             :     }
    1320             :   }
    1321          73 : }
    1322             : 
    1323             : /**
    1324             :  * InsertSheetInDoc handles ordering of sheets in the document.  Here
    1325             :  * we have two types of sheets -- those with linking elements and
    1326             :  * those without.  The latter are loaded by Link: headers.
    1327             :  * The following constraints are observed:
    1328             :  * 1) Any sheet with a linking element comes after all sheets without
    1329             :  *    linking elements
    1330             :  * 2) Sheets without linking elements are inserted in the order in
    1331             :  *    which the inserting requests come in, since all of these are
    1332             :  *    inserted during header data processing in the content sink
    1333             :  * 3) Sheets with linking elements are ordered based on document order
    1334             :  *    as determined by CompareDocumentPosition.
    1335             :  */
    1336             : nsresult
    1337          11 : Loader::InsertSheetInDoc(StyleSheet* aSheet,
    1338             :                          nsIContent* aLinkingContent,
    1339             :                          nsIDocument* aDocument)
    1340             : {
    1341          11 :   LOG(("css::Loader::InsertSheetInDoc"));
    1342          11 :   NS_PRECONDITION(aSheet, "Nothing to insert");
    1343          11 :   NS_PRECONDITION(aDocument, "Must have a document to insert into");
    1344             : 
    1345             :   // XXX Need to cancel pending sheet loads for this element, if any
    1346             : 
    1347          11 :   int32_t sheetCount = aDocument->GetNumberOfStyleSheets();
    1348             : 
    1349             :   /*
    1350             :    * Start the walk at the _end_ of the list, since in the typical
    1351             :    * case we'll just want to append anyway.  We want to break out of
    1352             :    * the loop when insertionPoint points to just before the index we
    1353             :    * want to insert at.  In other words, when we leave the loop
    1354             :    * insertionPoint is the index of the stylesheet that immediately
    1355             :    * precedes the one we're inserting.
    1356             :    */
    1357             :   int32_t insertionPoint;
    1358          11 :   for (insertionPoint = sheetCount - 1; insertionPoint >= 0; --insertionPoint) {
    1359           5 :     StyleSheet* curSheet = aDocument->GetStyleSheetAt(insertionPoint);
    1360           5 :     NS_ASSERTION(curSheet, "There must be a sheet here!");
    1361           5 :     nsCOMPtr<nsINode> sheetOwner = curSheet->GetOwnerNode();
    1362           5 :     if (sheetOwner && !aLinkingContent) {
    1363             :       // Keep moving; all sheets with a sheetOwner come after all
    1364             :       // sheets without a linkingNode
    1365           0 :       continue;
    1366             :     }
    1367             : 
    1368           5 :     if (!sheetOwner) {
    1369             :       // Aha!  The current sheet has no sheet owner, so we want to
    1370             :       // insert after it no matter whether we have a linkingNode
    1371           0 :       break;
    1372             :     }
    1373             : 
    1374           5 :     NS_ASSERTION(aLinkingContent != sheetOwner,
    1375             :                  "Why do we still have our old sheet?");
    1376             : 
    1377             :     // Have to compare
    1378           5 :     if (nsContentUtils::PositionIsBefore(sheetOwner, aLinkingContent)) {
    1379             :       // The current sheet comes before us, and it better be the first
    1380             :       // such, because now we break
    1381           5 :       break;
    1382             :     }
    1383             :   }
    1384             : 
    1385          11 :   ++insertionPoint; // adjust the index to the spot we want to insert in
    1386             : 
    1387             :   // XXX <meta> elements do not implement nsIStyleSheetLinkingElement;
    1388             :   // need to fix this for them to be ordered correctly.
    1389             :   nsCOMPtr<nsIStyleSheetLinkingElement>
    1390          22 :     linkingElement = do_QueryInterface(aLinkingContent);
    1391          11 :   if (linkingElement) {
    1392          11 :     linkingElement->SetStyleSheet(aSheet); // This sets the ownerNode on the sheet
    1393             :   }
    1394             : 
    1395          11 :   aDocument->BeginUpdate(UPDATE_STYLE);
    1396          11 :   aDocument->InsertStyleSheetAt(aSheet, insertionPoint);
    1397          11 :   aDocument->EndUpdate(UPDATE_STYLE);
    1398          11 :   LOG(("  Inserting into document at position %d", insertionPoint));
    1399             : 
    1400          22 :   return NS_OK;
    1401             : }
    1402             : 
    1403             : /**
    1404             :  * InsertChildSheet handles ordering of @import-ed sheet in their
    1405             :  * parent sheets.  Here we want to just insert based on order of the
    1406             :  * @import rules that imported the sheets.  In theory we can't just
    1407             :  * append to the end because the CSSOM can insert @import rules.  In
    1408             :  * practice, we get the call to load the child sheet before the CSSOM
    1409             :  * has finished inserting the @import rule, so we have no idea where
    1410             :  * to put it anyway.  So just append for now.  (In the future if we
    1411             :  * want to insert the sheet at the correct position, we'll need to
    1412             :  * restore CSSStyleSheet::InsertStyleSheetAt, which was removed in
    1413             :  * bug 1220506.)
    1414             :  */
    1415             : nsresult
    1416           3 : Loader::InsertChildSheet(StyleSheet* aSheet,
    1417             :                          StyleSheet* aParentSheet,
    1418             :                          ImportRule* aGeckoParentRule)
    1419             : {
    1420           3 :   LOG(("css::Loader::InsertChildSheet"));
    1421           3 :   MOZ_ASSERT(aSheet, "Nothing to insert");
    1422           3 :   MOZ_ASSERT(aParentSheet, "Need a parent to insert into");
    1423           3 :   MOZ_ASSERT(aSheet->IsGecko() == !!aGeckoParentRule);
    1424             : 
    1425             :   // child sheets should always start out enabled, even if they got
    1426             :   // cloned off of top-level sheets which were disabled
    1427           3 :   aSheet->SetEnabled(true);
    1428           3 :   if (aGeckoParentRule) {
    1429           3 :     aGeckoParentRule->SetSheet(aSheet->AsGecko()); // This sets the ownerRule on the sheet
    1430             :   }
    1431           3 :   aParentSheet->PrependStyleSheet(aSheet);
    1432             : 
    1433           3 :   LOG(("  Inserting into parent sheet"));
    1434           3 :   return NS_OK;
    1435             : }
    1436             : 
    1437             : /**
    1438             :  * LoadSheet handles the actual load of a sheet.  If the load is
    1439             :  * supposed to be synchronous it just opens a channel synchronously
    1440             :  * using the given uri, wraps the resulting stream in a converter
    1441             :  * stream and calls ParseSheet.  Otherwise it tries to look for an
    1442             :  * existing load for this URI and piggyback on it.  Failing all that,
    1443             :  * a new load is kicked off asynchronously.
    1444             :  */
    1445             : nsresult
    1446          53 : Loader::LoadSheet(SheetLoadData* aLoadData,
    1447             :                   StyleSheetState aSheetState,
    1448             :                   bool aIsPreload)
    1449             : {
    1450          53 :   LOG(("css::Loader::LoadSheet"));
    1451          53 :   NS_PRECONDITION(aLoadData, "Need a load data");
    1452          53 :   NS_PRECONDITION(aLoadData->mURI, "Need a URI to load");
    1453          53 :   NS_PRECONDITION(aLoadData->mSheet, "Need a sheet to load into");
    1454          53 :   NS_PRECONDITION(aSheetState != eSheetComplete, "Why bother?");
    1455          53 :   NS_PRECONDITION(!aLoadData->mUseSystemPrincipal || aLoadData->mSyncLoad,
    1456             :                   "Shouldn't use system principal for async loads");
    1457          53 :   NS_ASSERTION(mSheets, "mLoadingDatas should be initialized by now.");
    1458             : 
    1459          53 :   LOG_URI("  Load from: '%s'", aLoadData->mURI);
    1460             : 
    1461          53 :   nsresult rv = NS_OK;
    1462             : 
    1463          53 :   if (!mDocument && !aLoadData->mIsNonDocumentSheet) {
    1464             :     // No point starting the load; just release all the data and such.
    1465           0 :     LOG_WARN(("  No document and not non-document sheet; pre-dropping load"));
    1466           0 :     SheetComplete(aLoadData, NS_BINDING_ABORTED);
    1467           0 :     return NS_BINDING_ABORTED;
    1468             :   }
    1469             : 
    1470         106 :   SRIMetadata sriMetadata;
    1471          53 :   aLoadData->mSheet->GetIntegrity(sriMetadata);
    1472             : 
    1473          53 :   if (aLoadData->mSyncLoad) {
    1474          45 :     LOG(("  Synchronous load"));
    1475          45 :     NS_ASSERTION(!aLoadData->mObserver, "Observer for a sync load?");
    1476          45 :     NS_ASSERTION(aSheetState == eSheetNeedsParser,
    1477             :                  "Sync loads can't reuse existing async loads");
    1478             : 
    1479             :     // Create a nsIUnicharStreamLoader instance to which we will feed
    1480             :     // the data from the sync load.  Do this before creating the
    1481             :     // channel to make error recovery simpler.
    1482          90 :     nsCOMPtr<nsIUnicharStreamLoader> streamLoader;
    1483          45 :     rv = NS_NewUnicharStreamLoader(getter_AddRefs(streamLoader), aLoadData);
    1484          45 :     if (NS_FAILED(rv)) {
    1485           0 :       LOG_ERROR(("  Failed to create stream loader for sync load"));
    1486           0 :       SheetComplete(aLoadData, rv);
    1487           0 :       return rv;
    1488             :     }
    1489             : 
    1490          45 :     if (mDocument) {
    1491          19 :       mozilla::net::PredictorLearn(aLoadData->mURI, mDocument->GetDocumentURI(),
    1492             :                                    nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE,
    1493          19 :                                    mDocument);
    1494             :     }
    1495             : 
    1496             :     nsSecurityFlags securityFlags =
    1497             :       nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
    1498          45 :       nsILoadInfo::SEC_ALLOW_CHROME;
    1499             : 
    1500             :     nsContentPolicyType contentPolicyType =
    1501          45 :       aIsPreload ? nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD
    1502          45 :                  : nsIContentPolicy::TYPE_INTERNAL_STYLESHEET;
    1503             : 
    1504             :     // Just load it
    1505          90 :     nsCOMPtr<nsIChannel> channel;
    1506             :     // Note that we are calling NS_NewChannelWithTriggeringPrincipal() with both
    1507             :     // a node and a principal.
    1508             :     // This is because of a case where the node is the document being styled and
    1509             :     // the principal is the stylesheet (perhaps from a different origin) that is
    1510             :     // applying the styles.
    1511          45 :     if (aLoadData->mRequestingNode && aLoadData->mLoaderPrincipal) {
    1512           0 :       rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel),
    1513           0 :                                                 aLoadData->mURI,
    1514           0 :                                                 aLoadData->mRequestingNode,
    1515           0 :                                                 aLoadData->mLoaderPrincipal,
    1516             :                                                 securityFlags,
    1517           0 :                                                 contentPolicyType);
    1518             :     }
    1519             :     else {
    1520             :       // either we are loading something inside a document, in which case
    1521             :       // we should always have a requestingNode, or we are loading something
    1522             :       // outside a document, in which case the loadingPrincipal and the
    1523             :       // triggeringPrincipal should always be the systemPrincipal.
    1524         135 :       rv = NS_NewChannel(getter_AddRefs(channel),
    1525          45 :                          aLoadData->mURI,
    1526             :                          nsContentUtils::GetSystemPrincipal(),
    1527             :                          securityFlags,
    1528          45 :                          contentPolicyType);
    1529             :     }
    1530          45 :     if (NS_FAILED(rv)) {
    1531           0 :       LOG_ERROR(("  Failed to create channel"));
    1532           0 :       SheetComplete(aLoadData, rv);
    1533           0 :       return rv;
    1534             :     }
    1535             : 
    1536          90 :     nsCOMPtr<nsIInputStream> stream;
    1537          45 :     rv = channel->Open2(getter_AddRefs(stream));
    1538             : 
    1539          45 :     if (NS_FAILED(rv)) {
    1540           0 :       LOG_ERROR(("  Failed to open URI synchronously"));
    1541           0 :       SheetComplete(aLoadData, rv);
    1542           0 :       return rv;
    1543             :     }
    1544             : 
    1545             :     // Force UA sheets to be UTF-8.
    1546             :     // XXX this is only necessary because the default in
    1547             :     // SheetLoadData::OnDetermineCharset is wrong (bug 521039).
    1548          45 :     channel->SetContentCharset(NS_LITERAL_CSTRING("UTF-8"));
    1549             : 
    1550             :     // Manually feed the streamloader the contents of the stream.
    1551             :     // This will call back into OnStreamComplete
    1552             :     // and thence to ParseSheet.  Regardless of whether this fails,
    1553             :     // SheetComplete has been called.
    1554          90 :     return nsSyncLoadService::PushSyncStreamToListener(stream,
    1555             :                                                        streamLoader,
    1556          90 :                                                        channel);
    1557             :   }
    1558             : 
    1559           8 :   SheetLoadData* existingData = nullptr;
    1560             : 
    1561           8 :   URIPrincipalReferrerPolicyAndCORSModeHashKey key(aLoadData->mURI,
    1562           8 :                                      aLoadData->mLoaderPrincipal,
    1563           8 :                                      aLoadData->mSheet->GetCORSMode(),
    1564          40 :                                      aLoadData->mSheet->GetReferrerPolicy());
    1565           8 :   if (aSheetState == eSheetLoading) {
    1566           0 :     mSheets->mLoadingDatas.Get(&key, &existingData);
    1567           0 :     NS_ASSERTION(existingData, "CreateSheet lied about the state");
    1568             :   }
    1569           8 :   else if (aSheetState == eSheetPending){
    1570           0 :     mSheets->mPendingDatas.Get(&key, &existingData);
    1571           0 :     NS_ASSERTION(existingData, "CreateSheet lied about the state");
    1572             :   }
    1573             : 
    1574           8 :   if (existingData) {
    1575           0 :     LOG(("  Glomming on to existing load"));
    1576           0 :     SheetLoadData* data = existingData;
    1577           0 :     while (data->mNext) {
    1578           0 :       data = data->mNext;
    1579             :     }
    1580           0 :     data->mNext = aLoadData; // transfer ownership
    1581           0 :     if (aSheetState == eSheetPending && !aLoadData->mWasAlternate) {
    1582             :       // Kick the load off; someone cares about it right away
    1583             : 
    1584             : #ifdef DEBUG
    1585             :       SheetLoadData* removedData;
    1586           0 :       NS_ASSERTION(mSheets->mPendingDatas.Get(&key, &removedData) &&
    1587             :                    removedData == existingData,
    1588             :                    "Bad pending table.");
    1589             : #endif
    1590             : 
    1591           0 :       mSheets->mPendingDatas.Remove(&key);
    1592             : 
    1593           0 :       LOG(("  Forcing load of pending data"));
    1594           0 :       return LoadSheet(existingData, eSheetNeedsParser, aIsPreload);
    1595             :     }
    1596             :     // All done here; once the load completes we'll be marked complete
    1597             :     // automatically
    1598           0 :     return NS_OK;
    1599             :   }
    1600             : 
    1601          16 :   nsCOMPtr<nsILoadGroup> loadGroup;
    1602           8 :   if (mDocument) {
    1603           8 :     loadGroup = mDocument->GetDocumentLoadGroup();
    1604             :     // load for a document with no loadgrup indicates that something is
    1605             :     // completely bogus, let's bail out early.
    1606           8 :     if (!loadGroup) {
    1607           0 :       LOG_ERROR(("  Failed to query loadGroup from document"));
    1608           0 :       SheetComplete(aLoadData, NS_ERROR_UNEXPECTED);
    1609           0 :       return NS_ERROR_UNEXPECTED;
    1610             :     }
    1611             :   }
    1612             : #ifdef DEBUG
    1613           8 :   mSyncCallback = true;
    1614             : #endif
    1615             : 
    1616           8 :   CORSMode ourCORSMode = aLoadData->mSheet->GetCORSMode();
    1617             :   nsSecurityFlags securityFlags =
    1618             :     ourCORSMode == CORS_NONE
    1619           8 :       ? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS
    1620           8 :       : nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
    1621           8 :   if (ourCORSMode == CORS_ANONYMOUS) {
    1622           0 :     securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
    1623           8 :   } else if (ourCORSMode == CORS_USE_CREDENTIALS) {
    1624           0 :     securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
    1625             :   }
    1626           8 :   securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME;
    1627             : 
    1628             :   nsContentPolicyType contentPolicyType =
    1629           8 :     aIsPreload ? nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD
    1630           8 :                : nsIContentPolicy::TYPE_INTERNAL_STYLESHEET;
    1631             : 
    1632          16 :   nsCOMPtr<nsIChannel> channel;
    1633             :   // Note we are calling NS_NewChannelWithTriggeringPrincipal here with a node
    1634             :   // and a principal. This is because of a case where the node is the document
    1635             :   // being styled and the principal is the stylesheet (perhaps from a different
    1636             :   // origin)  that is applying the styles.
    1637           8 :   if (aLoadData->mRequestingNode && aLoadData->mLoaderPrincipal) {
    1638          40 :     rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(channel),
    1639           8 :                                               aLoadData->mURI,
    1640           8 :                                               aLoadData->mRequestingNode,
    1641           8 :                                               aLoadData->mLoaderPrincipal,
    1642             :                                               securityFlags,
    1643             :                                               contentPolicyType,
    1644             :                                               loadGroup,
    1645             :                                               nullptr,   // aCallbacks
    1646             :                                               nsIChannel::LOAD_NORMAL |
    1647           8 :                                               nsIChannel::LOAD_CLASSIFY_URI);
    1648             :   }
    1649             :   else {
    1650             :     // either we are loading something inside a document, in which case
    1651             :     // we should always have a requestingNode, or we are loading something
    1652             :     // outside a document, in which case the loadingPrincipal and the
    1653             :     // triggeringPrincipal should always be the systemPrincipal.
    1654           0 :     rv = NS_NewChannel(getter_AddRefs(channel),
    1655           0 :                        aLoadData->mURI,
    1656             :                        nsContentUtils::GetSystemPrincipal(),
    1657             :                        securityFlags,
    1658             :                        contentPolicyType,
    1659             :                        loadGroup,
    1660             :                        nullptr,   // aCallbacks
    1661             :                        nsIChannel::LOAD_NORMAL |
    1662           0 :                        nsIChannel::LOAD_CLASSIFY_URI);
    1663             :   }
    1664             : 
    1665           8 :   if (NS_FAILED(rv)) {
    1666             : #ifdef DEBUG
    1667           0 :     mSyncCallback = false;
    1668             : #endif
    1669           0 :     LOG_ERROR(("  Failed to create channel"));
    1670           0 :     SheetComplete(aLoadData, rv);
    1671           0 :     return rv;
    1672             :   }
    1673             : 
    1674           8 :   if (!aLoadData->mWasAlternate) {
    1675          16 :     nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(channel));
    1676           8 :     if (cos) {
    1677           0 :       cos->AddClassFlags(nsIClassOfService::Leader);
    1678             :     }
    1679             :   }
    1680             : 
    1681          16 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
    1682           8 :   if (httpChannel) {
    1683             :     // Send a minimal Accept header for text/css
    1684           0 :     rv = httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
    1685           0 :                                        NS_LITERAL_CSTRING("text/css,*/*;q=0.1"),
    1686           0 :                                        false);
    1687           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1688             : 
    1689           0 :     nsCOMPtr<nsIURI> referrerURI = aLoadData->GetReferrerURI();
    1690           0 :     if (referrerURI) {
    1691           0 :       rv = httpChannel->SetReferrerWithPolicy(referrerURI,
    1692           0 :                                               aLoadData->mSheet->GetReferrerPolicy());
    1693           0 :       Unused << NS_WARN_IF(NS_FAILED(rv));
    1694             :     }
    1695             : 
    1696           0 :     nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(httpChannel);
    1697           0 :     if (internalChannel) {
    1698           0 :       rv = internalChannel->SetIntegrityMetadata(sriMetadata.GetIntegrityString());
    1699           0 :       NS_ENSURE_SUCCESS(rv, rv);
    1700             :     }
    1701             : 
    1702             :     // Set the initiator type
    1703           0 :     nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChannel));
    1704           0 :     if (timedChannel) {
    1705           0 :       if (aLoadData->mParentData) {
    1706           0 :         timedChannel->SetInitiatorType(NS_LITERAL_STRING("css"));
    1707             :       } else {
    1708           0 :         timedChannel->SetInitiatorType(NS_LITERAL_STRING("link"));
    1709             :       }
    1710             :     }
    1711             :   }
    1712             : 
    1713             :   // Now tell the channel we expect text/css data back....  We do
    1714             :   // this before opening it, so it's only treated as a hint.
    1715           8 :   channel->SetContentType(NS_LITERAL_CSTRING("text/css"));
    1716             : 
    1717             :   // We don't have to hold on to the stream loader.  The ownership
    1718             :   // model is: Necko owns the stream loader, which owns the load data,
    1719             :   // which owns us
    1720          16 :   nsCOMPtr<nsIUnicharStreamLoader> streamLoader;
    1721           8 :   rv = NS_NewUnicharStreamLoader(getter_AddRefs(streamLoader), aLoadData);
    1722           8 :   if (NS_FAILED(rv)) {
    1723             : #ifdef DEBUG
    1724           0 :     mSyncCallback = false;
    1725             : #endif
    1726           0 :     LOG_ERROR(("  Failed to create stream loader"));
    1727           0 :     SheetComplete(aLoadData, rv);
    1728           0 :     return rv;
    1729             :   }
    1730             : 
    1731           8 :   if (mDocument) {
    1732           8 :     mozilla::net::PredictorLearn(aLoadData->mURI, mDocument->GetDocumentURI(),
    1733             :                                  nsINetworkPredictor::LEARN_LOAD_SUBRESOURCE,
    1734           8 :                                  mDocument);
    1735             :   }
    1736             : 
    1737           8 :   rv = channel->AsyncOpen2(streamLoader);
    1738             : 
    1739             : #ifdef DEBUG
    1740           8 :   mSyncCallback = false;
    1741             : #endif
    1742             : 
    1743           8 :   if (NS_FAILED(rv)) {
    1744           0 :     LOG_ERROR(("  Failed to create stream loader"));
    1745           0 :     SheetComplete(aLoadData, rv);
    1746           0 :     return rv;
    1747             :   }
    1748             : 
    1749           8 :   mSheets->mLoadingDatas.Put(&key, aLoadData);
    1750           8 :   aLoadData->mIsLoading = true;
    1751             : 
    1752           8 :   return NS_OK;
    1753             : }
    1754             : 
    1755             : /**
    1756             :  * ParseSheet handles parsing the data stream.  The main idea here is
    1757             :  * to push the current load data onto the parse stack before letting
    1758             :  * the CSS parser at the data stream.  That lets us handle @import
    1759             :  * correctly.
    1760             :  */
    1761             : nsresult
    1762          58 : Loader::ParseSheet(const nsAString& aInput,
    1763             :                    SheetLoadData* aLoadData,
    1764             :                    bool& aCompleted)
    1765             : {
    1766          58 :   LOG(("css::Loader::ParseSheet"));
    1767          58 :   NS_PRECONDITION(aLoadData, "Must have load data");
    1768          58 :   NS_PRECONDITION(aLoadData->mSheet, "Must have sheet to parse into");
    1769             : 
    1770          58 :   aCompleted = false;
    1771             : 
    1772             :   // Push our load data on the stack so any kids can pick it up
    1773          58 :   mParsingDatas.AppendElement(aLoadData);
    1774          58 :   nsIURI* sheetURI = aLoadData->mSheet->GetSheetURI();
    1775          58 :   nsIURI* baseURI = aLoadData->mSheet->GetBaseURI();
    1776             : 
    1777             :   nsresult rv;
    1778             : 
    1779          58 :   if (aLoadData->mSheet->IsGecko()) {
    1780         116 :     nsCSSParser parser(this, aLoadData->mSheet->AsGecko());
    1781         116 :     rv = parser.ParseSheet(aInput, sheetURI, baseURI,
    1782          58 :                            aLoadData->mSheet->Principal(),
    1783          58 :                            aLoadData->mLineNumber);
    1784             :   } else {
    1785             :     rv =
    1786           0 :       aLoadData->mSheet->AsServo()->ParseSheet(this,
    1787             :                                                aInput, sheetURI, baseURI,
    1788           0 :                                                aLoadData->mSheet->Principal(),
    1789             :                                                aLoadData->mLineNumber,
    1790           0 :                                                GetCompatibilityMode());
    1791             :   }
    1792             : 
    1793          58 :   mParsingDatas.RemoveElementAt(mParsingDatas.Length() - 1);
    1794             : 
    1795          58 :   if (NS_FAILED(rv)) {
    1796           0 :     LOG_ERROR(("  Low-level error in parser!"));
    1797           0 :     SheetComplete(aLoadData, rv);
    1798           0 :     return rv;
    1799             :   }
    1800             : 
    1801          58 :   NS_ASSERTION(aLoadData->mPendingChildren == 0 || !aLoadData->mSyncLoad,
    1802             :                "Sync load has leftover pending children!");
    1803             : 
    1804          58 :   if (aLoadData->mPendingChildren == 0) {
    1805          56 :     LOG(("  No pending kids from parse"));
    1806          56 :     aCompleted = true;
    1807          56 :     SheetComplete(aLoadData, NS_OK);
    1808             :   }
    1809             :   // Otherwise, the children are holding strong refs to the data and
    1810             :   // will call SheetComplete() on it when they complete.
    1811             : 
    1812          58 :   return NS_OK;
    1813             : }
    1814             : 
    1815             : /**
    1816             :  * SheetComplete is the do-it-all cleanup function.  It removes the
    1817             :  * load data from the "loading" hashtable, adds the sheet to the
    1818             :  * "completed" hashtable, massages the XUL cache, handles siblings of
    1819             :  * the load data (other loads for the same URI), handles unblocking
    1820             :  * blocked parent loads as needed, and most importantly calls
    1821             :  * NS_RELEASE on the load data to destroy the whole mess.
    1822             :  */
    1823             : void
    1824          56 : Loader::SheetComplete(SheetLoadData* aLoadData, nsresult aStatus)
    1825             : {
    1826          56 :   LOG(("css::Loader::SheetComplete"));
    1827             : 
    1828             :   // 8 is probably big enough for all our common cases.  It's not likely that
    1829             :   // imports will nest more than 8 deep, and multiple sheets with the same URI
    1830             :   // are rare.
    1831         112 :   AutoTArray<RefPtr<SheetLoadData>, 8> datasToNotify;
    1832          56 :   DoSheetComplete(aLoadData, aStatus, datasToNotify);
    1833             : 
    1834             :   // Now it's safe to go ahead and notify observers
    1835          56 :   uint32_t count = datasToNotify.Length();
    1836          56 :   mDatasToNotifyOn += count;
    1837          62 :   for (uint32_t i = 0; i < count; ++i) {
    1838           6 :     --mDatasToNotifyOn;
    1839             : 
    1840           6 :     SheetLoadData* data = datasToNotify[i];
    1841           6 :     NS_ASSERTION(data && data->mMustNotify, "How did this data get here?");
    1842           6 :     if (data->mObserver) {
    1843           6 :       LOG(("  Notifying observer %p for data %p.  wasAlternate: %d",
    1844             :            data->mObserver.get(), data, data->mWasAlternate));
    1845          12 :       data->mObserver->StyleSheetLoaded(data->mSheet, data->mWasAlternate,
    1846          12 :                                         aStatus);
    1847             :     }
    1848             : 
    1849          12 :     nsTObserverArray<nsCOMPtr<nsICSSLoaderObserver> >::ForwardIterator iter(mObservers);
    1850          12 :     nsCOMPtr<nsICSSLoaderObserver> obs;
    1851           6 :     while (iter.HasMore()) {
    1852           0 :       obs = iter.GetNext();
    1853           0 :       LOG(("  Notifying global observer %p for data %p.  wasAlternate: %d",
    1854             :            obs.get(), data, data->mWasAlternate));
    1855           0 :       obs->StyleSheetLoaded(data->mSheet, data->mWasAlternate, aStatus);
    1856             :     }
    1857             :   }
    1858             : 
    1859          56 :   if (mSheets->mLoadingDatas.Count() == 0 && mSheets->mPendingDatas.Count() > 0) {
    1860           0 :     LOG(("  No more loading sheets; starting alternates"));
    1861           0 :     StartAlternateLoads();
    1862             :   }
    1863          56 : }
    1864             : 
    1865             : void
    1866          58 : Loader::DoSheetComplete(SheetLoadData* aLoadData, nsresult aStatus,
    1867             :                         LoadDataArray& aDatasToNotify)
    1868             : {
    1869          58 :   LOG(("css::Loader::DoSheetComplete"));
    1870          58 :   NS_PRECONDITION(aLoadData, "Must have a load data!");
    1871          58 :   NS_PRECONDITION(aLoadData->mSheet, "Must have a sheet");
    1872          58 :   NS_ASSERTION(mSheets, "mLoadingDatas should be initialized by now.");
    1873             : 
    1874          58 :   LOG(("Load completed, status: 0x%" PRIx32, static_cast<uint32_t>(aStatus)));
    1875             : 
    1876             :   // Twiddle the hashtables
    1877          58 :   if (aLoadData->mURI) {
    1878          53 :     LOG_URI("  Finished loading: '%s'", aLoadData->mURI);
    1879             :     // Remove the data from the list of loading datas
    1880          53 :     if (aLoadData->mIsLoading) {
    1881             :       URIPrincipalReferrerPolicyAndCORSModeHashKey key(aLoadData->mURI,
    1882             :                                          aLoadData->mLoaderPrincipal,
    1883           8 :                                          aLoadData->mSheet->GetCORSMode(),
    1884          24 :                                          aLoadData->mSheet->GetReferrerPolicy());
    1885             : #ifdef DEBUG
    1886             :       SheetLoadData *loadingData;
    1887           8 :       NS_ASSERTION(
    1888             :         mSheets->mLoadingDatas.Get(&key, &loadingData) &&
    1889             :         loadingData == aLoadData,
    1890             :         "Bad loading table");
    1891             : #endif
    1892             : 
    1893           8 :       mSheets->mLoadingDatas.Remove(&key);
    1894           8 :       aLoadData->mIsLoading = false;
    1895             :     }
    1896             :   }
    1897             : 
    1898             :   // Go through and deal with the whole linked list.
    1899          58 :   SheetLoadData* data = aLoadData;
    1900         174 :   while (data) {
    1901          58 :     if (!data->mSheetAlreadyComplete) {
    1902             :       // If mSheetAlreadyComplete, then the sheet could well be modified between
    1903             :       // when we posted the async call to SheetComplete and now, since the sheet
    1904             :       // was page-accessible during that whole time.
    1905          58 :       MOZ_ASSERT(!data->mSheet->IsModified(),
    1906             :                  "should not get marked modified during parsing");
    1907          58 :       data->mSheet->SetComplete();
    1908          58 :       data->ScheduleLoadEventIfNeeded(aStatus);
    1909             :     }
    1910          58 :     if (data->mMustNotify && (data->mObserver || !mObservers.IsEmpty())) {
    1911             :       // Don't notify here so we don't trigger script.  Remember the
    1912             :       // info we need to notify, then do it later when it's safe.
    1913           6 :       aDatasToNotify.AppendElement(data);
    1914             : 
    1915             :       // On append failure, just press on.  We'll fail to notify the observer,
    1916             :       // but not much we can do about that....
    1917             :     }
    1918             : 
    1919          58 :     NS_ASSERTION(!data->mParentData ||
    1920             :                  data->mParentData->mPendingChildren != 0,
    1921             :                  "Broken pending child count on our parent");
    1922             : 
    1923             :     // If we have a parent, our parent is no longer being parsed, and
    1924             :     // we are the last pending child, then our load completion
    1925             :     // completes the parent too.  Note that the parent _can_ still be
    1926             :     // being parsed (eg if the child (us) failed to open the channel
    1927             :     // or some such).
    1928         122 :     if (data->mParentData &&
    1929          64 :         --(data->mParentData->mPendingChildren) == 0 &&
    1930           3 :         !mParsingDatas.Contains(data->mParentData)) {
    1931           2 :       DoSheetComplete(data->mParentData, aStatus, aDatasToNotify);
    1932             :     }
    1933             : 
    1934          58 :     data = data->mNext;
    1935             :   }
    1936             : 
    1937             :   // Now that it's marked complete, put the sheet in our cache.
    1938             :   // If we ever start doing this for failure aStatus, we'll need to
    1939             :   // adjust the PostLoadEvent code that thinks anything already
    1940             :   // complete must have loaded succesfully.
    1941          58 :   if (NS_SUCCEEDED(aStatus) && aLoadData->mURI) {
    1942             :     // Pick our sheet to cache carefully.  Ideally, we want to cache
    1943             :     // one of the sheets that will be kept alive by a document or
    1944             :     // parent sheet anyway, so that if someone then accesses it via
    1945             :     // CSSOM we won't have extra clones of the inner lying around.
    1946          53 :     data = aLoadData;
    1947          53 :     StyleSheet* sheet = aLoadData->mSheet;
    1948         141 :     while (data) {
    1949          53 :       if (data->mSheet->GetParentSheet() || data->mSheet->GetOwnerNode()) {
    1950           9 :         sheet = data->mSheet;
    1951           9 :         break;
    1952             :       }
    1953          44 :       data = data->mNext;
    1954             :     }
    1955             : #ifdef MOZ_XUL
    1956          53 :     if (IsChromeURI(aLoadData->mURI)) {
    1957          37 :       nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
    1958          37 :       if (cache && cache->IsEnabled()) {
    1959          37 :         if (!cache->GetStyleSheet(aLoadData->mURI, GetStyleBackendType())) {
    1960          37 :           LOG(("  Putting sheet in XUL prototype cache"));
    1961          37 :           NS_ASSERTION(sheet->IsComplete(),
    1962             :                        "Should only be caching complete sheets");
    1963          37 :           cache->PutStyleSheet(sheet, GetStyleBackendType());
    1964             :         }
    1965             :       }
    1966             :     }
    1967             :     else {
    1968             : #endif
    1969             :       URIPrincipalReferrerPolicyAndCORSModeHashKey key(aLoadData->mURI,
    1970             :                                          aLoadData->mLoaderPrincipal,
    1971          16 :                                          aLoadData->mSheet->GetCORSMode(),
    1972          48 :                                          aLoadData->mSheet->GetReferrerPolicy());
    1973          16 :       NS_ASSERTION(sheet->IsComplete(),
    1974             :                    "Should only be caching complete sheets");
    1975          16 :       mSheets->mCompleteSheets.Put(&key, sheet);
    1976             : #ifdef MOZ_XUL
    1977             :     }
    1978             : #endif
    1979             :   }
    1980             : 
    1981          58 :   NS_RELEASE(aLoadData);  // this will release parents and siblings and all that
    1982          58 : }
    1983             : 
    1984             : nsresult
    1985           5 : Loader::LoadInlineStyle(nsIContent* aElement,
    1986             :                         const nsAString& aBuffer,
    1987             :                         uint32_t aLineNumber,
    1988             :                         const nsAString& aTitle,
    1989             :                         const nsAString& aMedia,
    1990             :                         Element* aScopeElement,
    1991             :                         nsICSSLoaderObserver* aObserver,
    1992             :                         bool* aCompleted,
    1993             :                         bool* aIsAlternate)
    1994             : {
    1995           5 :   LOG(("css::Loader::LoadInlineStyle"));
    1996           5 :   MOZ_ASSERT(mParsingDatas.IsEmpty(), "We're in the middle of a parse?");
    1997             : 
    1998           5 :   *aCompleted = true;
    1999             : 
    2000           5 :   if (!mEnabled) {
    2001           0 :     LOG_WARN(("  Not enabled"));
    2002           0 :     return NS_ERROR_NOT_AVAILABLE;
    2003             :   }
    2004             : 
    2005           5 :   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_INITIALIZED);
    2006             : 
    2007          10 :   nsCOMPtr<nsIStyleSheetLinkingElement> owningElement(do_QueryInterface(aElement));
    2008           5 :   NS_ASSERTION(owningElement, "Element is not a style linking element!");
    2009             : 
    2010             :   // Since we're not planning to load a URI, no need to hand a principal to the
    2011             :   // load data or to CreateSheet().  Also, OK to use CORS_NONE for the CORS
    2012             :   // mode and mDocument's ReferrerPolicy.
    2013             :   StyleSheetState state;
    2014          10 :   RefPtr<StyleSheet> sheet;
    2015          10 :   nsresult rv = CreateSheet(nullptr, aElement, nullptr, eAuthorSheetFeatures,
    2016           5 :                             CORS_NONE, mDocument->GetReferrerPolicy(),
    2017           5 :                             EmptyString(), // no inline integrity checks
    2018             :                             false, false, aTitle, state, aIsAlternate,
    2019           5 :                             &sheet);
    2020           5 :   NS_ENSURE_SUCCESS(rv, rv);
    2021           5 :   NS_ASSERTION(state == eSheetNeedsParser,
    2022             :                "Inline sheets should not be cached");
    2023             : 
    2024           5 :   LOG(("  Sheet is alternate: %d", *aIsAlternate));
    2025             : 
    2026           5 :   PrepareSheet(sheet, aTitle, aMedia, nullptr, aScopeElement, *aIsAlternate);
    2027             : 
    2028           5 :   if (aElement->HasFlag(NODE_IS_IN_SHADOW_TREE)) {
    2029           0 :     ShadowRoot* containingShadow = aElement->GetContainingShadow();
    2030           0 :     MOZ_ASSERT(containingShadow);
    2031           0 :     containingShadow->InsertSheet(sheet, aElement);
    2032             :   } else {
    2033           5 :     rv = InsertSheetInDoc(sheet, aElement, mDocument);
    2034           5 :     NS_ENSURE_SUCCESS(rv, rv);
    2035             :   }
    2036             : 
    2037             :   SheetLoadData* data = new SheetLoadData(this, aTitle, nullptr, sheet,
    2038           5 :                                           owningElement, *aIsAlternate,
    2039          15 :                                           aObserver, nullptr, static_cast<nsINode*>(aElement));
    2040             : 
    2041             :   // We never actually load this, so just set its principal directly
    2042           5 :   sheet->SetPrincipal(aElement->NodePrincipal());
    2043             : 
    2044           5 :   NS_ADDREF(data);
    2045           5 :   data->mLineNumber = aLineNumber;
    2046             :   // Parse completion releases the load data
    2047           5 :   rv = ParseSheet(aBuffer, data, *aCompleted);
    2048           5 :   NS_ENSURE_SUCCESS(rv, rv);
    2049             : 
    2050             :   // If aCompleted is true, |data| may well be deleted by now.
    2051           5 :   if (!*aCompleted) {
    2052           0 :     data->mMustNotify = true;
    2053             :   }
    2054           5 :   return rv;
    2055             : }
    2056             : 
    2057             : nsresult
    2058           6 : Loader::LoadStyleLink(nsIContent* aElement,
    2059             :                       nsIURI* aURL,
    2060             :                       const nsAString& aTitle,
    2061             :                       const nsAString& aMedia,
    2062             :                       bool aHasAlternateRel,
    2063             :                       CORSMode aCORSMode,
    2064             :                       ReferrerPolicy aReferrerPolicy,
    2065             :                       const nsAString& aIntegrity,
    2066             :                       nsICSSLoaderObserver* aObserver,
    2067             :                       bool* aIsAlternate)
    2068             : {
    2069           6 :   LOG(("css::Loader::LoadStyleLink"));
    2070           6 :   NS_PRECONDITION(aURL, "Must have URL to load");
    2071           6 :   NS_ASSERTION(mParsingDatas.Length() == 0, "We're in the middle of a parse?");
    2072             : 
    2073           6 :   LOG_URI("  Link uri: '%s'", aURL);
    2074           6 :   LOG(("  Link title: '%s'", NS_ConvertUTF16toUTF8(aTitle).get()));
    2075           6 :   LOG(("  Link media: '%s'", NS_ConvertUTF16toUTF8(aMedia).get()));
    2076           6 :   LOG(("  Link alternate rel: %d", aHasAlternateRel));
    2077             : 
    2078           6 :   if (!mEnabled) {
    2079           0 :     LOG_WARN(("  Not enabled"));
    2080           0 :     return NS_ERROR_NOT_AVAILABLE;
    2081             :   }
    2082             : 
    2083           6 :   NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_INITIALIZED);
    2084             : 
    2085             :   nsIPrincipal* principal =
    2086           6 :     aElement ? aElement->NodePrincipal() : mDocument->NodePrincipal();
    2087             : 
    2088           6 :   nsISupports* context = aElement;
    2089           6 :   if (!context) {
    2090           0 :     context = mDocument;
    2091             :   }
    2092             : 
    2093           6 :   nsresult rv = CheckContentPolicy(principal, aURL, context, false);
    2094           6 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2095             :     // Don't fire the error event if our document is loaded as data.  We're
    2096             :     // supposed to not even try to do loads in that case... Unfortunately, we
    2097             :     // implement that via nsDataDocumentContentPolicy, which doesn't have a good
    2098             :     // way to communicate back to us that _it_ is the thing that blocked the
    2099             :     // load.
    2100           0 :     if (aElement && !mDocument->IsLoadedAsData()) {
    2101             :       // Fire an async error event on it.
    2102             :       RefPtr<AsyncEventDispatcher> loadBlockingAsyncDispatcher =
    2103             :         new LoadBlockingAsyncEventDispatcher(aElement,
    2104           0 :                                              NS_LITERAL_STRING("error"),
    2105           0 :                                              false, false);
    2106           0 :       loadBlockingAsyncDispatcher->PostDOMEvent();
    2107             :     }
    2108           0 :     return rv;
    2109             :   }
    2110             : 
    2111             :   StyleSheetState state;
    2112          12 :   RefPtr<StyleSheet> sheet;
    2113           6 :   rv = CreateSheet(aURL, aElement, principal, eAuthorSheetFeatures,
    2114             :                    aCORSMode, aReferrerPolicy, aIntegrity, false,
    2115             :                    aHasAlternateRel, aTitle, state, aIsAlternate,
    2116           6 :                    &sheet);
    2117           6 :   NS_ENSURE_SUCCESS(rv, rv);
    2118             : 
    2119           6 :   LOG(("  Sheet is alternate: %d", *aIsAlternate));
    2120             : 
    2121           6 :   PrepareSheet(sheet, aTitle, aMedia, nullptr, nullptr, *aIsAlternate);
    2122             : 
    2123           6 :   rv = InsertSheetInDoc(sheet, aElement, mDocument);
    2124           6 :   NS_ENSURE_SUCCESS(rv, rv);
    2125             : 
    2126          12 :   nsCOMPtr<nsIStyleSheetLinkingElement> owningElement(do_QueryInterface(aElement));
    2127             : 
    2128           6 :   if (state == eSheetComplete) {
    2129           0 :     LOG(("  Sheet already complete: 0x%p", sheet.get()));
    2130           0 :     if (aObserver || !mObservers.IsEmpty() || owningElement) {
    2131           0 :       rv = PostLoadEvent(aURL, sheet, aObserver, *aIsAlternate,
    2132           0 :                          owningElement);
    2133           0 :       return rv;
    2134             :     }
    2135             : 
    2136           0 :     return NS_OK;
    2137             :   }
    2138             : 
    2139             :   // Now we need to actually load it
    2140          12 :   nsCOMPtr<nsINode> requestingNode = do_QueryInterface(context);
    2141             :   SheetLoadData* data = new SheetLoadData(this, aTitle, aURL, sheet,
    2142           6 :                                           owningElement, *aIsAlternate,
    2143          18 :                                           aObserver, principal, requestingNode);
    2144           6 :   NS_ADDREF(data);
    2145             : 
    2146             :   // If we have to parse and it's an alternate non-inline, defer it
    2147          11 :   if (aURL && state == eSheetNeedsParser && mSheets->mLoadingDatas.Count() != 0 &&
    2148           5 :       *aIsAlternate) {
    2149           0 :     LOG(("  Deferring alternate sheet load"));
    2150           0 :     URIPrincipalReferrerPolicyAndCORSModeHashKey key(data->mURI,
    2151           0 :                                                      data->mLoaderPrincipal,
    2152           0 :                                                      data->mSheet->GetCORSMode(),
    2153           0 :                                                      data->mSheet->GetReferrerPolicy());
    2154           0 :     mSheets->mPendingDatas.Put(&key, data);
    2155             : 
    2156           0 :     data->mMustNotify = true;
    2157           0 :     return NS_OK;
    2158             :   }
    2159             : 
    2160             :   // Load completion will free the data
    2161           6 :   rv = LoadSheet(data, state, false);
    2162           6 :   NS_ENSURE_SUCCESS(rv, rv);
    2163             : 
    2164           6 :   data->mMustNotify = true;
    2165           6 :   return rv;
    2166             : }
    2167             : 
    2168             : static bool
    2169           4 : HaveAncestorDataWithURI(SheetLoadData *aData, nsIURI *aURI)
    2170             : {
    2171           4 :   if (!aData->mURI) {
    2172             :     // Inline style; this won't have any ancestors
    2173           0 :     MOZ_ASSERT(!aData->mParentData,
    2174             :                "How does inline style have a parent?");
    2175           0 :     return false;
    2176             :   }
    2177             : 
    2178             :   bool equal;
    2179           4 :   if (NS_FAILED(aData->mURI->Equals(aURI, &equal)) || equal) {
    2180           0 :     return true;
    2181             :   }
    2182             : 
    2183             :   // Datas down the mNext chain have the same URI as aData, so we
    2184             :   // don't have to compare to them.  But they might have different
    2185             :   // parents, and we have to check all of those.
    2186          12 :   while (aData) {
    2187           5 :     if (aData->mParentData &&
    2188           5 :         HaveAncestorDataWithURI(aData->mParentData, aURI)) {
    2189           0 :       return true;
    2190             :     }
    2191             : 
    2192           4 :     aData = aData->mNext;
    2193             :   }
    2194             : 
    2195           4 :   return false;
    2196             : }
    2197             : 
    2198             : nsresult
    2199           3 : Loader::LoadChildSheet(StyleSheet* aParentSheet,
    2200             :                        nsIURI* aURL,
    2201             :                        dom::MediaList* aMedia,
    2202             :                        ImportRule* aGeckoParentRule,
    2203             :                        LoaderReusableStyleSheets* aReusableSheets)
    2204             : {
    2205           3 :   LOG(("css::Loader::LoadChildSheet"));
    2206           3 :   NS_PRECONDITION(aURL, "Must have a URI to load");
    2207           3 :   NS_PRECONDITION(aParentSheet, "Must have a parent sheet");
    2208           3 :   MOZ_ASSERT(aParentSheet->IsGecko() == !!aGeckoParentRule);
    2209             : 
    2210           3 :   if (!mEnabled) {
    2211           0 :     LOG_WARN(("  Not enabled"));
    2212           0 :     return NS_ERROR_NOT_AVAILABLE;
    2213             :   }
    2214             : 
    2215           3 :   LOG_URI("  Child uri: '%s'", aURL);
    2216             : 
    2217           6 :   nsCOMPtr<nsINode> owningNode;
    2218             : 
    2219             :   // check for an associated document: if none, don't bother walking up the
    2220             :   // parent sheets
    2221           3 :   if (aParentSheet->GetAssociatedDocument()) {
    2222           2 :     StyleSheet* topSheet = aParentSheet;
    2223           3 :     while (StyleSheet* parent = topSheet->GetParentSheet()) {
    2224           1 :       topSheet = parent;
    2225           1 :     }
    2226           2 :     owningNode = topSheet->GetOwnerNode();
    2227             :   }
    2228             : 
    2229           3 :   nsISupports* context = owningNode;
    2230           3 :   if (!context) {
    2231           1 :     context = mDocument;
    2232             :   }
    2233             : 
    2234           3 :   nsIPrincipal* principal = aParentSheet->Principal();
    2235           3 :   nsresult rv = CheckContentPolicy(principal, aURL, context, false);
    2236           3 :   NS_ENSURE_SUCCESS(rv, rv);
    2237             : 
    2238           3 :   SheetLoadData* parentData = nullptr;
    2239           6 :   nsCOMPtr<nsICSSLoaderObserver> observer;
    2240             : 
    2241           3 :   int32_t count = mParsingDatas.Length();
    2242           3 :   if (count > 0) {
    2243           3 :     LOG(("  Have a parent load"));
    2244           3 :     parentData = mParsingDatas.ElementAt(count - 1);
    2245             :     // Check for cycles
    2246           3 :     if (HaveAncestorDataWithURI(parentData, aURL)) {
    2247             :       // Houston, we have a loop, blow off this child and pretend this never
    2248             :       // happened
    2249           0 :       LOG_ERROR(("  @import cycle detected, dropping load"));
    2250           0 :       return NS_OK;
    2251             :     }
    2252             : 
    2253           3 :     NS_ASSERTION(parentData->mSheet == aParentSheet,
    2254             :                  "Unexpected call to LoadChildSheet");
    2255             :   } else {
    2256           0 :     LOG(("  No parent load; must be CSSOM"));
    2257             :     // No parent load data, so the sheet will need to be notified when
    2258             :     // we finish, if it can be, if we do the load asynchronously.
    2259           0 :     observer = aParentSheet;
    2260             :   }
    2261             : 
    2262             :   // Now that we know it's safe to load this (passes security check and not a
    2263             :   // loop) do so.
    2264           6 :   RefPtr<StyleSheet> sheet;
    2265             :   StyleSheetState state;
    2266           3 :   if (aReusableSheets && aReusableSheets->FindReusableStyleSheet(aURL, sheet)) {
    2267           0 :     if (aParentSheet->IsGecko()) {
    2268           0 :       aGeckoParentRule->SetSheet(sheet->AsGecko());
    2269             :     }
    2270           0 :     state = eSheetComplete;
    2271             :   } else {
    2272             :     bool isAlternate;
    2273           3 :     const nsAString& empty = EmptyString();
    2274             :     // For now, use CORS_NONE for child sheets
    2275          12 :     rv = CreateSheet(aURL, nullptr, principal,
    2276           3 :                      aParentSheet->ParsingMode(),
    2277             :                      CORS_NONE, aParentSheet->GetReferrerPolicy(),
    2278           3 :                      EmptyString(), // integrity is only checked on main sheet
    2279           3 :                      parentData ? parentData->mSyncLoad : false,
    2280           3 :                      false, empty, state, &isAlternate, &sheet);
    2281           3 :     NS_ENSURE_SUCCESS(rv, rv);
    2282             : 
    2283           3 :     PrepareSheet(sheet, empty, empty, aMedia, nullptr, isAlternate);
    2284             :   }
    2285             : 
    2286           3 :   rv = InsertChildSheet(sheet, aParentSheet, aGeckoParentRule);
    2287           3 :   NS_ENSURE_SUCCESS(rv, rv);
    2288             : 
    2289           3 :   if (state == eSheetComplete) {
    2290           0 :     LOG(("  Sheet already complete"));
    2291             :     // We're completely done.  No need to notify, even, since the
    2292             :     // @import rule addition/modification will trigger the right style
    2293             :     // changes automatically.
    2294           0 :     return NS_OK;
    2295             :   }
    2296             : 
    2297           6 :   nsCOMPtr<nsINode> requestingNode = do_QueryInterface(context);
    2298             :   SheetLoadData* data = new SheetLoadData(this, aURL, sheet, parentData,
    2299           6 :                                           observer, principal, requestingNode);
    2300             : 
    2301           3 :   NS_ADDREF(data);
    2302           3 :   bool syncLoad = data->mSyncLoad;
    2303             : 
    2304             :   // Load completion will release the data
    2305           3 :   rv = LoadSheet(data, state, false);
    2306           3 :   NS_ENSURE_SUCCESS(rv, rv);
    2307             : 
    2308             :   // If syncLoad is true, |data| will be deleted by now.
    2309           3 :   if (!syncLoad) {
    2310           2 :     data->mMustNotify = true;
    2311             :   }
    2312           3 :   return rv;
    2313             : }
    2314             : 
    2315             : nsresult
    2316          59 : Loader::LoadSheetSync(nsIURI* aURL,
    2317             :                       SheetParsingMode aParsingMode,
    2318             :                       bool aUseSystemPrincipal,
    2319             :                       RefPtr<StyleSheet>* aSheet)
    2320             : {
    2321          59 :   LOG(("css::Loader::LoadSheetSync"));
    2322          59 :   return InternalLoadNonDocumentSheet(aURL,
    2323             :                                       false, aParsingMode, aUseSystemPrincipal,
    2324             :                                       nullptr, EmptyCString(),
    2325          59 :                                       aSheet, nullptr);
    2326             : }
    2327             : 
    2328             : nsresult
    2329           0 : Loader::LoadSheet(nsIURI* aURL,
    2330             :                   SheetParsingMode aParsingMode,
    2331             :                   bool aUseSystemPrincipal,
    2332             :                   nsICSSLoaderObserver* aObserver,
    2333             :                   RefPtr<StyleSheet>* aSheet)
    2334             : {
    2335           0 :   LOG(("css::Loader::LoadSheet(aURL, aParsingMode, aUseSystemPrincipal, aObserver, aSheet)"));
    2336           0 :   return InternalLoadNonDocumentSheet(aURL,
    2337             :                                       false, aParsingMode, aUseSystemPrincipal,
    2338             :                                       nullptr, EmptyCString(),
    2339           0 :                                       aSheet, aObserver);
    2340             : }
    2341             : 
    2342             : nsresult
    2343           0 : Loader::LoadSheet(nsIURI* aURL,
    2344             :                   nsIPrincipal* aOriginPrincipal,
    2345             :                   const nsCString& aCharset,
    2346             :                   nsICSSLoaderObserver* aObserver,
    2347             :                   RefPtr<StyleSheet>* aSheet)
    2348             : {
    2349           0 :   LOG(("css::Loader::LoadSheet(aURL, aObserver, aSheet) api call"));
    2350           0 :   NS_PRECONDITION(aSheet, "aSheet is null");
    2351           0 :   return InternalLoadNonDocumentSheet(aURL,
    2352             :                                       false, eAuthorSheetFeatures, false,
    2353             :                                       aOriginPrincipal, aCharset,
    2354           0 :                                       aSheet, aObserver);
    2355             : }
    2356             : 
    2357             : nsresult
    2358           0 : Loader::LoadSheet(nsIURI* aURL,
    2359             :                   bool aIsPreload,
    2360             :                   nsIPrincipal* aOriginPrincipal,
    2361             :                   const nsCString& aCharset,
    2362             :                   nsICSSLoaderObserver* aObserver,
    2363             :                   CORSMode aCORSMode,
    2364             :                   ReferrerPolicy aReferrerPolicy,
    2365             :                   const nsAString& aIntegrity)
    2366             : {
    2367           0 :   LOG(("css::Loader::LoadSheet(aURL, aObserver) api call"));
    2368           0 :   return InternalLoadNonDocumentSheet(aURL,
    2369             :                                       aIsPreload, eAuthorSheetFeatures, false,
    2370             :                                       aOriginPrincipal, aCharset,
    2371             :                                       nullptr, aObserver,
    2372           0 :                                       aCORSMode, aReferrerPolicy, aIntegrity);
    2373             : }
    2374             : 
    2375             : nsresult
    2376          59 : Loader::InternalLoadNonDocumentSheet(nsIURI* aURL,
    2377             :                                      bool aIsPreload,
    2378             :                                      SheetParsingMode aParsingMode,
    2379             :                                      bool aUseSystemPrincipal,
    2380             :                                      nsIPrincipal* aOriginPrincipal,
    2381             :                                      const nsCString& aCharset,
    2382             :                                      RefPtr<StyleSheet>* aSheet,
    2383             :                                      nsICSSLoaderObserver* aObserver,
    2384             :                                      CORSMode aCORSMode,
    2385             :                                      ReferrerPolicy aReferrerPolicy,
    2386             :                                      const nsAString& aIntegrity)
    2387             : {
    2388          59 :   NS_PRECONDITION(aURL, "Must have a URI to load");
    2389          59 :   NS_PRECONDITION(aSheet || aObserver, "Sheet and observer can't both be null");
    2390          59 :   NS_PRECONDITION(!aUseSystemPrincipal || !aObserver,
    2391             :                   "Shouldn't load system-principal sheets async");
    2392          59 :   NS_ASSERTION(mParsingDatas.Length() == 0, "We're in the middle of a parse?");
    2393             : 
    2394          59 :   LOG_URI("  Non-document sheet uri: '%s'", aURL);
    2395             : 
    2396          59 :   if (aSheet) {
    2397          59 :     *aSheet = nullptr;
    2398             :   }
    2399             : 
    2400          59 :   if (!mEnabled) {
    2401           0 :     LOG_WARN(("  Not enabled"));
    2402           0 :     return NS_ERROR_NOT_AVAILABLE;
    2403             :   }
    2404             : 
    2405          59 :   nsresult rv = CheckContentPolicy(aOriginPrincipal, aURL, mDocument, aIsPreload);
    2406          59 :   NS_ENSURE_SUCCESS(rv, rv);
    2407             : 
    2408             :   StyleSheetState state;
    2409             :   bool isAlternate;
    2410         118 :   RefPtr<StyleSheet> sheet;
    2411          59 :   bool syncLoad = (aObserver == nullptr);
    2412          59 :   const nsAString& empty = EmptyString();
    2413             : 
    2414          59 :   rv = CreateSheet(aURL, nullptr, aOriginPrincipal, aParsingMode,
    2415             :                    aCORSMode, aReferrerPolicy, aIntegrity, syncLoad,
    2416          59 :                    false, empty, state, &isAlternate, &sheet);
    2417          59 :   NS_ENSURE_SUCCESS(rv, rv);
    2418             : 
    2419          59 :   PrepareSheet(sheet, empty, empty, nullptr, nullptr, isAlternate);
    2420             : 
    2421          59 :   if (state == eSheetComplete) {
    2422          15 :     LOG(("  Sheet already complete"));
    2423          15 :     if (aObserver || !mObservers.IsEmpty()) {
    2424           0 :       rv = PostLoadEvent(aURL, sheet, aObserver, false, nullptr);
    2425             :     }
    2426          15 :     if (aSheet) {
    2427          15 :       sheet.swap(*aSheet);
    2428             :     }
    2429          15 :     return rv;
    2430             :   }
    2431             : 
    2432             :   SheetLoadData* data =
    2433             :     new SheetLoadData(this, aURL, sheet, syncLoad,
    2434             :                       aUseSystemPrincipal, aCharset, aObserver,
    2435          88 :                       aOriginPrincipal, mDocument);
    2436             : 
    2437          44 :   NS_ADDREF(data);
    2438          44 :   rv = LoadSheet(data, state, aIsPreload);
    2439          44 :   NS_ENSURE_SUCCESS(rv, rv);
    2440             : 
    2441          44 :   if (aSheet) {
    2442          44 :     sheet.swap(*aSheet);
    2443             :   }
    2444          44 :   if (aObserver) {
    2445           0 :     data->mMustNotify = true;
    2446             :   }
    2447             : 
    2448          44 :   return rv;
    2449             : }
    2450             : 
    2451             : nsresult
    2452           0 : Loader::PostLoadEvent(nsIURI* aURI,
    2453             :                       StyleSheet* aSheet,
    2454             :                       nsICSSLoaderObserver* aObserver,
    2455             :                       bool aWasAlternate,
    2456             :                       nsIStyleSheetLinkingElement* aElement)
    2457             : {
    2458           0 :   LOG(("css::Loader::PostLoadEvent"));
    2459           0 :   NS_PRECONDITION(aSheet, "Must have sheet");
    2460           0 :   NS_PRECONDITION(aObserver || !mObservers.IsEmpty() || aElement,
    2461             :                   "Must have observer or element");
    2462             : 
    2463             :   RefPtr<SheetLoadData> evt =
    2464           0 :     new SheetLoadData(this, EmptyString(), // title doesn't matter here
    2465             :                       aURI,
    2466             :                       aSheet,
    2467             :                       aElement,
    2468             :                       aWasAlternate,
    2469             :                       aObserver,
    2470             :                       nullptr,
    2471           0 :                       mDocument);
    2472             : 
    2473           0 :   if (!mPostedEvents.AppendElement(evt)) {
    2474           0 :     return NS_ERROR_OUT_OF_MEMORY;
    2475             :   }
    2476             : 
    2477             :   nsresult rv;
    2478           0 :   RefPtr<SheetLoadData> runnable(evt);
    2479           0 :   if (mDocument) {
    2480           0 :     rv = mDocument->Dispatch("SheetLoadData", TaskCategory::Other,
    2481           0 :                              runnable.forget());
    2482           0 :   } else if (mDocGroup) {
    2483           0 :     rv = mDocGroup->Dispatch("SheetLoadData", TaskCategory::Other,
    2484           0 :                              runnable.forget());
    2485             :   } else {
    2486           0 :     rv = SystemGroup::Dispatch("SheetLoadData", TaskCategory::Other,
    2487           0 :                                runnable.forget());
    2488             :   }
    2489             : 
    2490           0 :   if (NS_FAILED(rv)) {
    2491           0 :     NS_WARNING("failed to dispatch stylesheet load event");
    2492           0 :     mPostedEvents.RemoveElement(evt);
    2493             :   } else {
    2494             :     // We'll unblock onload when we handle the event.
    2495           0 :     if (mDocument) {
    2496           0 :       mDocument->BlockOnload();
    2497             :     }
    2498             : 
    2499             :     // We want to notify the observer for this data.
    2500           0 :     evt->mMustNotify = true;
    2501           0 :     evt->mSheetAlreadyComplete = true;
    2502             : 
    2503             :     // If we get to this code, aSheet loaded correctly at some point, so
    2504             :     // we can just use NS_OK for the status.  Note that we do this here
    2505             :     // and not from inside our SheetComplete so that we don't end up
    2506             :     // running the load event async.
    2507           0 :     evt->ScheduleLoadEventIfNeeded(NS_OK);
    2508             :   }
    2509             : 
    2510           0 :   return rv;
    2511             : }
    2512             : 
    2513             : void
    2514           0 : Loader::HandleLoadEvent(SheetLoadData* aEvent)
    2515             : {
    2516             :   // XXXbz can't assert this yet.... May not have an observer because
    2517             :   // we're unblocking the parser
    2518             :   // NS_ASSERTION(aEvent->mObserver, "Must have observer");
    2519           0 :   NS_ASSERTION(aEvent->mSheet, "Must have sheet");
    2520             : 
    2521             :   // Very important: this needs to come before the SheetComplete call
    2522             :   // below, so that HasPendingLoads() will test true as needed under
    2523             :   // notifications we send from that SheetComplete call.
    2524           0 :   mPostedEvents.RemoveElement(aEvent);
    2525             : 
    2526           0 :   if (!aEvent->mIsCancelled) {
    2527             :     // SheetComplete will call Release(), so give it a reference to do
    2528             :     // that with.
    2529           0 :     NS_ADDREF(aEvent);
    2530           0 :     SheetComplete(aEvent, NS_OK);
    2531             :   }
    2532             : 
    2533           0 :   if (mDocument) {
    2534           0 :     mDocument->UnblockOnload(true);
    2535             :   }
    2536           0 : }
    2537             : 
    2538             : static void
    2539           0 : StopLoadingSheets(
    2540             :   nsDataHashtable<URIPrincipalReferrerPolicyAndCORSModeHashKey, SheetLoadData*>& aDatas,
    2541             :   Loader::LoadDataArray& aArr)
    2542             : {
    2543           0 :   for (auto iter = aDatas.Iter(); !iter.Done(); iter.Next()) {
    2544           0 :     SheetLoadData* data = iter.Data();
    2545           0 :     MOZ_ASSERT(data, "Must have a data!");
    2546             : 
    2547           0 :     data->mIsLoading = false; // we will handle the removal right here
    2548           0 :     data->mIsCancelled = true;
    2549             : 
    2550           0 :     aArr.AppendElement(data);
    2551             : 
    2552           0 :     iter.Remove();
    2553             :   }
    2554           0 : }
    2555             : 
    2556             : nsresult
    2557           0 : Loader::Stop()
    2558             : {
    2559           0 :   uint32_t pendingCount = mSheets ? mSheets->mPendingDatas.Count() : 0;
    2560           0 :   uint32_t loadingCount = mSheets ? mSheets->mLoadingDatas.Count() : 0;
    2561           0 :   LoadDataArray arr(pendingCount + loadingCount + mPostedEvents.Length());
    2562             : 
    2563           0 :   if (pendingCount) {
    2564           0 :     StopLoadingSheets(mSheets->mPendingDatas, arr);
    2565             :   }
    2566           0 :   if (loadingCount) {
    2567           0 :     StopLoadingSheets(mSheets->mLoadingDatas, arr);
    2568             :   }
    2569             : 
    2570             :   uint32_t i;
    2571           0 :   for (i = 0; i < mPostedEvents.Length(); ++i) {
    2572           0 :     SheetLoadData* data = mPostedEvents[i];
    2573           0 :     data->mIsCancelled = true;
    2574           0 :     if (arr.AppendElement(data)) {
    2575             :       // SheetComplete() calls Release(), so give this an extra ref.
    2576           0 :       NS_ADDREF(data);
    2577             :     }
    2578             : #ifdef DEBUG
    2579             :     else {
    2580           0 :       NS_NOTREACHED("We preallocated this memory... shouldn't really fail, "
    2581             :                     "except we never check that preallocation succeeds.");
    2582             :     }
    2583             : #endif
    2584             :   }
    2585           0 :   mPostedEvents.Clear();
    2586             : 
    2587           0 :   mDatasToNotifyOn += arr.Length();
    2588           0 :   for (i = 0; i < arr.Length(); ++i) {
    2589           0 :     --mDatasToNotifyOn;
    2590           0 :     SheetComplete(arr[i], NS_BINDING_ABORTED);
    2591             :   }
    2592           0 :   return NS_OK;
    2593             : }
    2594             : 
    2595             : bool
    2596           0 : Loader::HasPendingLoads()
    2597             : {
    2598             :   return
    2599           0 :     (mSheets && mSheets->mLoadingDatas.Count() != 0) ||
    2600           0 :     (mSheets && mSheets->mPendingDatas.Count() != 0) ||
    2601           0 :     mPostedEvents.Length() != 0 ||
    2602           0 :     mDatasToNotifyOn != 0;
    2603             : }
    2604             : 
    2605             : nsresult
    2606           0 : Loader::AddObserver(nsICSSLoaderObserver* aObserver)
    2607             : {
    2608           0 :   NS_PRECONDITION(aObserver, "Must have observer");
    2609           0 :   if (mObservers.AppendElementUnlessExists(aObserver)) {
    2610           0 :     return NS_OK;
    2611             :   }
    2612             : 
    2613           0 :   return NS_ERROR_OUT_OF_MEMORY;
    2614             : }
    2615             : 
    2616             : void
    2617           0 : Loader::RemoveObserver(nsICSSLoaderObserver* aObserver)
    2618             : {
    2619           0 :   mObservers.RemoveElement(aObserver);
    2620           0 : }
    2621             : 
    2622             : void
    2623           0 : Loader::StartAlternateLoads()
    2624             : {
    2625           0 :   NS_PRECONDITION(mSheets, "Don't call me!");
    2626           0 :   LoadDataArray arr(mSheets->mPendingDatas.Count());
    2627           0 :   for (auto iter = mSheets->mPendingDatas.Iter(); !iter.Done(); iter.Next()) {
    2628           0 :     arr.AppendElement(iter.Data());
    2629           0 :     iter.Remove();
    2630             :   }
    2631             : 
    2632           0 :   mDatasToNotifyOn += arr.Length();
    2633           0 :   for (uint32_t i = 0; i < arr.Length(); ++i) {
    2634           0 :     --mDatasToNotifyOn;
    2635           0 :     LoadSheet(arr[i], eSheetNeedsParser, false);
    2636             :   }
    2637           0 : }
    2638             : 
    2639             : NS_IMPL_CYCLE_COLLECTION_CLASS(Loader)
    2640             : 
    2641           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Loader)
    2642           0 :   if (tmp->mSheets) {
    2643           0 :     for (auto iter = tmp->mSheets->mCompleteSheets.Iter();
    2644           0 :          !iter.Done();
    2645           0 :          iter.Next()) {
    2646           0 :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "Sheet cache nsCSSLoader");
    2647           0 :       cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIDOMCSSStyleSheet*, iter.UserData()));
    2648             :     }
    2649             :   }
    2650             :   nsTObserverArray<nsCOMPtr<nsICSSLoaderObserver>>::ForwardIterator
    2651           0 :     it(tmp->mObservers);
    2652           0 :   while (it.HasMore()) {
    2653           0 :     ImplCycleCollectionTraverse(cb, it.GetNext(),
    2654           0 :                                 "mozilla::css::Loader.mObservers");
    2655             :   }
    2656           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    2657             : 
    2658           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Loader)
    2659           0 :   if (tmp->mSheets) {
    2660           0 :     tmp->mSheets->mCompleteSheets.Clear();
    2661             :   }
    2662           0 :   tmp->mObservers.Clear();
    2663           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    2664             : 
    2665           0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(Loader, AddRef)
    2666           0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(Loader, Release)
    2667             : 
    2668             : size_t
    2669          21 : Loader::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
    2670             : {
    2671          21 :   size_t n = aMallocSizeOf(this);
    2672             : 
    2673          21 :   if (mSheets) {
    2674           5 :     n += mSheets->mCompleteSheets.ShallowSizeOfExcludingThis(aMallocSizeOf);
    2675          10 :     for (auto iter = mSheets->mCompleteSheets.ConstIter();
    2676           5 :          !iter.Done();
    2677           0 :          iter.Next()) {
    2678             :       // If aSheet has a parent, then its parent will report it so we don't
    2679             :       // have to worry about it here. Likewise, if aSheet has an owning node,
    2680             :       // then the document that node is in will report it.
    2681           0 :       const StyleSheet* sheet = iter.UserData();
    2682           0 :       n += (sheet->GetOwnerNode() || sheet->GetParentSheet())
    2683           0 :          ? 0
    2684           0 :          : sheet->SizeOfIncludingThis(aMallocSizeOf);
    2685             :     }
    2686             :   }
    2687          21 :   n += mObservers.ShallowSizeOfExcludingThis(aMallocSizeOf);
    2688             : 
    2689             :   // Measurement of the following members may be added later if DMD finds it is
    2690             :   // worthwhile:
    2691             :   // - mLoadingDatas: transient, and should be small
    2692             :   // - mPendingDatas: transient, and should be small
    2693             :   // - mParsingDatas: transient, and should be small
    2694             :   // - mPostedEvents: transient, and should be small
    2695             :   //
    2696             :   // The following members aren't measured:
    2697             :   // - mDocument, because it's a weak backpointer
    2698             :   // - mPreferredSheet, because it can be a shared string
    2699             : 
    2700          21 :   return n;
    2701             : }
    2702             : 
    2703             : StyleBackendType
    2704         184 : Loader::GetStyleBackendType() const
    2705             : {
    2706         184 :   MOZ_ASSERT(mStyleBackendType || mDocument,
    2707             :              "you must construct a Loader with a document or set a "
    2708             :              "StyleBackendType on it before calling GetStyleBackendType");
    2709         184 :   if (mStyleBackendType) {
    2710          56 :     return *mStyleBackendType;
    2711             :   }
    2712         128 :   return mDocument->GetStyleBackendType();
    2713             : }
    2714             : 
    2715             : } // namespace css
    2716             : } // namespace mozilla

Generated by: LCOV version 1.13