LCOV - code coverage report
Current view: directory - layout/style - Loader.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 883 18 2.0 %
Date: 2012-06-02 Functions: 57 7 12.3 %

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

Generated by: LCOV version 1.7