layout/style/Loader.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /* loading of CSS style sheets using the network APIs */
     8 #ifndef mozilla_css_Loader_h
     9 #define mozilla_css_Loader_h
    11 #include "nsIPrincipal.h"
    12 #include "nsAString.h"
    13 #include "nsAutoPtr.h"
    14 #include "nsCompatibility.h"
    15 #include "nsDataHashtable.h"
    16 #include "nsInterfaceHashtable.h"
    17 #include "nsRefPtrHashtable.h"
    18 #include "nsTArray.h"
    19 #include "nsTObserverArray.h"
    20 #include "nsURIHashKey.h"
    21 #include "mozilla/Attributes.h"
    22 #include "mozilla/CORSMode.h"
    23 #include "mozilla/MemoryReporting.h"
    25 class nsIAtom;
    26 class nsICSSLoaderObserver;
    27 class nsCSSStyleSheet;
    28 class nsIContent;
    29 class nsIDocument;
    30 class nsCSSParser;
    31 class nsMediaList;
    32 class nsIStyleSheetLinkingElement;
    33 class nsCycleCollectionTraversalCallback;
    35 namespace mozilla {
    36 namespace dom {
    37 class Element;
    38 }
    39 }
    41 namespace mozilla {
    43 class URIPrincipalAndCORSModeHashKey : public nsURIHashKey
    44 {
    45 public:
    46   typedef URIPrincipalAndCORSModeHashKey* KeyType;
    47   typedef const URIPrincipalAndCORSModeHashKey* KeyTypePointer;
    49   URIPrincipalAndCORSModeHashKey(const URIPrincipalAndCORSModeHashKey* aKey)
    50     : nsURIHashKey(aKey->mKey), mPrincipal(aKey->mPrincipal),
    51       mCORSMode(aKey->mCORSMode)
    52   {
    53     MOZ_COUNT_CTOR(URIPrincipalAndCORSModeHashKey);
    54   }
    55   URIPrincipalAndCORSModeHashKey(nsIURI* aURI, nsIPrincipal* aPrincipal,
    56                                  CORSMode aCORSMode)
    57     : nsURIHashKey(aURI), mPrincipal(aPrincipal), mCORSMode(aCORSMode)
    58   {
    59     MOZ_COUNT_CTOR(URIPrincipalAndCORSModeHashKey);
    60   }
    61   URIPrincipalAndCORSModeHashKey(const URIPrincipalAndCORSModeHashKey& toCopy)
    62     : nsURIHashKey(toCopy), mPrincipal(toCopy.mPrincipal),
    63       mCORSMode(toCopy.mCORSMode)
    64   {
    65     MOZ_COUNT_CTOR(URIPrincipalAndCORSModeHashKey);
    66   }
    67   ~URIPrincipalAndCORSModeHashKey()
    68   {
    69     MOZ_COUNT_DTOR(URIPrincipalAndCORSModeHashKey);
    70   }
    72   URIPrincipalAndCORSModeHashKey* GetKey() const {
    73     return const_cast<URIPrincipalAndCORSModeHashKey*>(this);
    74   }
    75   const URIPrincipalAndCORSModeHashKey* GetKeyPointer() const { return this; }
    77   bool KeyEquals(const URIPrincipalAndCORSModeHashKey* aKey) const {
    78     if (!nsURIHashKey::KeyEquals(aKey->mKey)) {
    79       return false;
    80     }
    82     if (!mPrincipal != !aKey->mPrincipal) {
    83       // One or the other has a principal, but not both... not equal
    84       return false;
    85     }
    87     if (mCORSMode != aKey->mCORSMode) {
    88       // Different CORS modes; we don't match
    89       return false;
    90     }
    92     bool eq;
    93     return !mPrincipal ||
    94       (NS_SUCCEEDED(mPrincipal->Equals(aKey->mPrincipal, &eq)) && eq);
    95   }
    97   static const URIPrincipalAndCORSModeHashKey*
    98   KeyToPointer(URIPrincipalAndCORSModeHashKey* aKey) { return aKey; }
    99   static PLDHashNumber HashKey(const URIPrincipalAndCORSModeHashKey* aKey) {
   100     return nsURIHashKey::HashKey(aKey->mKey);
   101   }
   103   nsIURI* GetURI() const { return nsURIHashKey::GetKey(); }
   105   enum { ALLOW_MEMMOVE = true };
   107 protected:
   108   nsCOMPtr<nsIPrincipal> mPrincipal;
   109   CORSMode mCORSMode;
   110 };
   114 namespace css {
   116 class SheetLoadData;
   117 class ImportRule;
   119 /***********************************************************************
   120  * Enum that describes the state of the sheet returned by CreateSheet. *
   121  ***********************************************************************/
   122 enum StyleSheetState {
   123   eSheetStateUnknown = 0,
   124   eSheetNeedsParser,
   125   eSheetPending,
   126   eSheetLoading,
   127   eSheetComplete
   128 };
   130 class Loader MOZ_FINAL {
   131 public:
   132   Loader();
   133   Loader(nsIDocument*);
   135  private:
   136   // Private destructor, to discourage deletion outside of Release():
   137   ~Loader();
   139  public:
   140   NS_INLINE_DECL_REFCOUNTING(Loader)
   142   void DropDocumentReference(); // notification that doc is going away
   144   void SetCompatibilityMode(nsCompatibility aCompatMode)
   145   { mCompatMode = aCompatMode; }
   146   nsCompatibility GetCompatibilityMode() { return mCompatMode; }
   147   nsresult SetPreferredSheet(const nsAString& aTitle);
   149   // XXXbz sort out what the deal is with events!  When should they fire?
   151   /**
   152    * Load an inline style sheet.  If a successful result is returned and
   153    * *aCompleted is false, then aObserver is guaranteed to be notified
   154    * asynchronously once the sheet is marked complete.  If an error is
   155    * returned, or if *aCompleted is true, aObserver will not be notified.  In
   156    * addition to parsing the sheet, this method will insert it into the
   157    * stylesheet list of this CSSLoader's document.
   158    *
   159    * @param aElement the element linking to the stylesheet.  This must not be
   160    *                 null and must implement nsIStyleSheetLinkingElement.
   161    * @param aBuffer the stylesheet data
   162    * @param aLineNumber the line number at which the stylesheet data started.
   163    * @param aTitle the title of the sheet.
   164    * @param aMedia the media string for the sheet.
   165    * @param aObserver the observer to notify when the load completes.
   166    *        May be null.
   167    * @param [out] aCompleted whether parsing of the sheet completed.
   168    * @param [out] aIsAlternate whether the stylesheet ended up being an
   169    *        alternate sheet.
   170    */
   171   nsresult LoadInlineStyle(nsIContent* aElement,
   172                            const nsAString& aBuffer,
   173                            uint32_t aLineNumber,
   174                            const nsAString& aTitle,
   175                            const nsAString& aMedia,
   176                            mozilla::dom::Element* aScopeElement,
   177                            nsICSSLoaderObserver* aObserver,
   178                            bool* aCompleted,
   179                            bool* aIsAlternate);
   181   /**
   182    * Load a linked (document) stylesheet.  If a successful result is returned,
   183    * aObserver is guaranteed to be notified asynchronously once the sheet is
   184    * loaded and marked complete.  If an error is returned, aObserver will not
   185    * be notified.  In addition to loading the sheet, this method will insert it
   186    * into the stylesheet list of this CSSLoader's document.
   187    *
   188    * @param aElement the element linking to the the stylesheet.  May be null.
   189    * @param aURL the URL of the sheet.
   190    * @param aTitle the title of the sheet.
   191    * @param aMedia the media string for the sheet.
   192    * @param aHasAlternateRel whether the rel for this link included
   193    *        "alternate".
   194    * @param aCORSMode the CORS mode for this load.
   195    * @param aObserver the observer to notify when the load completes.
   196    *                  May be null.
   197    * @param [out] aIsAlternate whether the stylesheet actually ended up beinga
   198    *        an alternate sheet.  Note that this need not match
   199    *        aHasAlternateRel.
   200    */
   201   nsresult LoadStyleLink(nsIContent* aElement,
   202                          nsIURI* aURL,
   203                          const nsAString& aTitle,
   204                          const nsAString& aMedia,
   205                          bool aHasAlternateRel,
   206                          CORSMode aCORSMode,
   207                          nsICSSLoaderObserver* aObserver,
   208                          bool* aIsAlternate);
   210   /**
   211    * Load a child (@import-ed) style sheet.  In addition to loading the sheet,
   212    * this method will insert it into the child sheet list of aParentSheet.  If
   213    * there is no sheet currently being parsed and the child sheet is not
   214    * complete when this method returns, then when the child sheet becomes
   215    * complete aParentSheet will be QIed to nsICSSLoaderObserver and
   216    * asynchronously notified, just like for LoadStyleLink.  Note that if the
   217    * child sheet is already complete when this method returns, no
   218    * nsICSSLoaderObserver notification will be sent.
   219    *
   220    * @param aParentSheet the parent of this child sheet
   221    * @param aURL the URL of the child sheet
   222    * @param aMedia the already-parsed media list for the child sheet
   223    * @param aRule the @import rule importing this child.  This is used to
   224    *              properly order the child sheet list of aParentSheet.
   225    */
   226   nsresult LoadChildSheet(nsCSSStyleSheet* aParentSheet,
   227                           nsIURI* aURL,
   228                           nsMediaList* aMedia,
   229                           ImportRule* aRule);
   231   /**
   232    * Synchronously load and return the stylesheet at aURL.  Any child sheets
   233    * will also be loaded synchronously.  Note that synchronous loads over some
   234    * protocols may involve spinning up a new event loop, so use of this method
   235    * does NOT guarantee not receiving any events before the sheet loads.  This
   236    * method can be used to load sheets not associated with a document.
   237    *
   238    * @param aURL the URL of the sheet to load
   239    * @param aEnableUnsafeRules whether unsafe rules are enabled for this
   240    * sheet load
   241    * Unsafe rules are rules that can violate key Gecko invariants if misused.
   242    * In particular, most anonymous box pseudoelements must be very carefully
   243    * styled or we will have severe problems. Therefore unsafe rules should
   244    * never be enabled for stylesheets controlled by untrusted sites; preferably
   245    * unsafe rules should only be enabled for agent sheets.
   246    * @param aUseSystemPrincipal if true, give the resulting sheet the system
   247    * principal no matter where it's being loaded from.
   248    * @param [out] aSheet the loaded, complete sheet.
   249    *
   250    * NOTE: At the moment, this method assumes the sheet will be UTF-8, but
   251    * ideally it would allow arbitrary encodings.  Callers should NOT depend on
   252    * non-UTF8 sheets being treated as UTF-8 by this method.
   253    *
   254    * NOTE: A successful return from this method doesn't indicate anything about
   255    * whether the data could be parsed as CSS and doesn't indicate anything
   256    * about the status of child sheets of the returned sheet.
   257    */
   258   nsresult LoadSheetSync(nsIURI* aURL, bool aEnableUnsafeRules,
   259                          bool aUseSystemPrincipal,
   260                          nsCSSStyleSheet** aSheet);
   262   /**
   263    * As above, but aUseSystemPrincipal and aEnableUnsafeRules are assumed false.
   264    */
   265   nsresult LoadSheetSync(nsIURI* aURL, nsCSSStyleSheet** aSheet) {
   266     return LoadSheetSync(aURL, false, false, aSheet);
   267   }
   269   /**
   270    * Asynchronously load the stylesheet at aURL.  If a successful result is
   271    * returned, aObserver is guaranteed to be notified asynchronously once the
   272    * sheet is loaded and marked complete.  This method can be used to load
   273    * sheets not associated with a document.
   274    *
   275    * @param aURL the URL of the sheet to load
   276    * @param aOriginPrincipal the principal to use for security checks.  This
   277    *                         can be null to indicate that these checks should
   278    *                         be skipped.
   279    * @param aCharset the encoding to use for converting the sheet data
   280    *        from bytes to Unicode.  May be empty to indicate that the
   281    *        charset of the CSSLoader's document should be used.  This
   282    *        is only used if neither the network transport nor the
   283    *        sheet itself indicate an encoding.
   284    * @param aObserver the observer to notify when the load completes.
   285    *                  Must not be null.
   286    * @param [out] aSheet the sheet to load. Note that the sheet may well
   287    *              not be loaded by the time this method returns.
   288    */
   289   nsresult LoadSheet(nsIURI* aURL,
   290                      nsIPrincipal* aOriginPrincipal,
   291                      const nsCString& aCharset,
   292                      nsICSSLoaderObserver* aObserver,
   293                      nsCSSStyleSheet** aSheet);
   295   /**
   296    * Same as above, to be used when the caller doesn't care about the
   297    * not-yet-loaded sheet.
   298    */
   299   nsresult LoadSheet(nsIURI* aURL,
   300                      nsIPrincipal* aOriginPrincipal,
   301                      const nsCString& aCharset,
   302                      nsICSSLoaderObserver* aObserver,
   303                      CORSMode aCORSMode = CORS_NONE);
   305   /**
   306    * Stop loading all sheets.  All nsICSSLoaderObservers involved will be
   307    * notified with NS_BINDING_ABORTED as the status, possibly synchronously.
   308    */
   309   nsresult Stop(void);
   311   /**
   312    * nsresult Loader::StopLoadingSheet(nsIURI* aURL), which notifies the
   313    * nsICSSLoaderObserver with NS_BINDING_ABORTED, was removed in Bug 556446.
   314    * It can be found in revision 2c44a32052ad.
   315    */
   317   /**
   318    * Whether the loader is enabled or not.
   319    * When disabled, processing of new styles is disabled and an attempt
   320    * to do so will fail with a return code of
   321    * NS_ERROR_NOT_AVAILABLE. Note that this DOES NOT disable
   322    * currently loading styles or already processed styles.
   323    */
   324   bool GetEnabled() { return mEnabled; }
   325   void SetEnabled(bool aEnabled) { mEnabled = aEnabled; }
   327   /**
   328    * Get the document we live for. May return null.
   329    */
   330   nsIDocument* GetDocument() const { return mDocument; }
   332   /**
   333    * Return true if this loader has pending loads (ones that would send
   334    * notifications to an nsICSSLoaderObserver attached to this loader).
   335    * If called from inside nsICSSLoaderObserver::StyleSheetLoaded, this will
   336    * return false if and only if that is the last StyleSheetLoaded
   337    * notification the CSSLoader knows it's going to send.  In other words, if
   338    * two sheets load at once (via load coalescing, e.g.), HasPendingLoads()
   339    * will return true during notification for the first one, and false
   340    * during notification for the second one.
   341    */
   342   bool HasPendingLoads();
   344   /**
   345    * Add an observer to this loader.  The observer will be notified
   346    * for all loads that would have notified their own observers (even
   347    * if those loads don't have observers attached to them).
   348    * Load-specific observers will be notified before generic
   349    * observers.  The loader holds a reference to the observer.
   350    *
   351    * aObserver must not be null.
   352    */
   353   nsresult AddObserver(nsICSSLoaderObserver* aObserver);
   355   /**
   356    * Remove an observer added via AddObserver.
   357    */
   358   void RemoveObserver(nsICSSLoaderObserver* aObserver);
   360   // These interfaces are public only for the benefit of static functions
   361   // within nsCSSLoader.cpp.
   363   // IsAlternate can change our currently selected style set if none
   364   // is selected and aHasAlternateRel is false.
   365   bool IsAlternate(const nsAString& aTitle, bool aHasAlternateRel);
   367   typedef nsTArray<nsRefPtr<SheetLoadData> > LoadDataArray;
   369   // Traverse the cached stylesheets we're holding on to.  This should
   370   // only be called from the document that owns this loader.
   371   void TraverseCachedSheets(nsCycleCollectionTraversalCallback& cb);
   373   // Unlink the cached stylesheets we're holding on to.  Again, this
   374   // should only be called from the document that owns this loader.
   375   void UnlinkCachedSheets();
   377   // Measure our size.
   378   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
   380   // Marks all the sheets at the given URI obsolete, and removes them from the
   381   // cache.
   382   nsresult ObsoleteSheet(nsIURI* aURI);
   384 private:
   385   friend class SheetLoadData;
   387   static PLDHashOperator
   388   RemoveEntriesWithURI(URIPrincipalAndCORSModeHashKey* aKey,
   389                        nsRefPtr<nsCSSStyleSheet> &aSheet,
   390                        void* aUserData);
   392   // Note: null aSourcePrincipal indicates that the content policy and
   393   // CheckLoadURI checks should be skipped.
   394   nsresult CheckLoadAllowed(nsIPrincipal* aSourcePrincipal,
   395                             nsIURI* aTargetURI,
   396                             nsISupports* aContext);
   399   // For inline style, the aURI param is null, but the aLinkingContent
   400   // must be non-null then.  The loader principal must never be null
   401   // if aURI is not null.
   402   // *aIsAlternate is set based on aTitle and aHasAlternateRel.
   403   nsresult CreateSheet(nsIURI* aURI,
   404                        nsIContent* aLinkingContent,
   405                        nsIPrincipal* aLoaderPrincipal,
   406                        CORSMode aCORSMode,
   407                        bool aSyncLoad,
   408                        bool aHasAlternateRel,
   409                        const nsAString& aTitle,
   410                        StyleSheetState& aSheetState,
   411                        bool *aIsAlternate,
   412                        nsCSSStyleSheet** aSheet);
   414   // Pass in either a media string or the nsMediaList from the
   415   // CSSParser.  Don't pass both.
   416   // This method will set the sheet's enabled state based on isAlternate
   417   void PrepareSheet(nsCSSStyleSheet* aSheet,
   418                     const nsAString& aTitle,
   419                     const nsAString& aMediaString,
   420                     nsMediaList* aMediaList,
   421                     dom::Element* aScopeElement,
   422                     bool isAlternate);
   424   nsresult InsertSheetInDoc(nsCSSStyleSheet* aSheet,
   425                             nsIContent* aLinkingContent,
   426                             nsIDocument* aDocument);
   428   nsresult InsertChildSheet(nsCSSStyleSheet* aSheet,
   429                             nsCSSStyleSheet* aParentSheet,
   430                             ImportRule* aParentRule);
   432   nsresult InternalLoadNonDocumentSheet(nsIURI* aURL,
   433                                         bool aAllowUnsafeRules,
   434                                         bool aUseSystemPrincipal,
   435                                         nsIPrincipal* aOriginPrincipal,
   436                                         const nsCString& aCharset,
   437                                         nsCSSStyleSheet** aSheet,
   438                                         nsICSSLoaderObserver* aObserver,
   439                                         CORSMode aCORSMode = CORS_NONE);
   441   // Post a load event for aObserver to be notified about aSheet.  The
   442   // notification will be sent with status NS_OK unless the load event is
   443   // canceled at some point (in which case it will be sent with
   444   // NS_BINDING_ABORTED).  aWasAlternate indicates the state when the load was
   445   // initiated, not the state at some later time.  aURI should be the URI the
   446   // sheet was loaded from (may be null for inline sheets).  aElement is the
   447   // owning element for this sheet.
   448   nsresult PostLoadEvent(nsIURI* aURI,
   449                          nsCSSStyleSheet* aSheet,
   450                          nsICSSLoaderObserver* aObserver,
   451                          bool aWasAlternate,
   452                          nsIStyleSheetLinkingElement* aElement);
   454   // Start the loads of all the sheets in mPendingDatas
   455   void StartAlternateLoads();
   457   // Handle an event posted by PostLoadEvent
   458   void HandleLoadEvent(SheetLoadData* aEvent);
   460   // Note: LoadSheet is responsible for releasing aLoadData and setting the
   461   // sheet to complete on failure.
   462   nsresult LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState);
   464   // Parse the stylesheet in aLoadData.  The sheet data comes from aInput.
   465   // Set aCompleted to true if the parse finished, false otherwise (e.g. if the
   466   // sheet had an @import).  If aCompleted is true when this returns, then
   467   // ParseSheet also called SheetComplete on aLoadData.
   468   nsresult ParseSheet(const nsAString& aInput,
   469                       SheetLoadData* aLoadData,
   470                       bool& aCompleted);
   472   // The load of the sheet in aLoadData is done, one way or another.  Do final
   473   // cleanup, including releasing aLoadData.
   474   void SheetComplete(SheetLoadData* aLoadData, nsresult aStatus);
   476   // The guts of SheetComplete.  This may be called recursively on parent datas
   477   // or datas that had glommed on to a single load.  The array is there so load
   478   // datas whose observers need to be notified can be added to it.
   479   void DoSheetComplete(SheetLoadData* aLoadData, nsresult aStatus,
   480                        LoadDataArray& aDatasToNotify);
   482   struct Sheets {
   483     nsRefPtrHashtable<URIPrincipalAndCORSModeHashKey, nsCSSStyleSheet>
   484                       mCompleteSheets;
   485     nsDataHashtable<URIPrincipalAndCORSModeHashKey, SheetLoadData*>
   486                       mLoadingDatas; // weak refs
   487     nsDataHashtable<URIPrincipalAndCORSModeHashKey, SheetLoadData*>
   488                       mPendingDatas; // weak refs
   489   };
   490   nsAutoPtr<Sheets> mSheets;
   492   // We're not likely to have many levels of @import...  But likely to have
   493   // some.  Allocate some storage, what the hell.
   494   nsAutoTArray<SheetLoadData*, 8> mParsingDatas;
   496   // The array of posted stylesheet loaded events (SheetLoadDatas) we have.
   497   // Note that these are rare.
   498   LoadDataArray     mPostedEvents;
   500   // Our array of "global" observers
   501   // XXXbz these are strong refs; should we be cycle collecting CSS loaders?
   502   nsTObserverArray<nsCOMPtr<nsICSSLoaderObserver> > mObservers;
   504   // the load data needs access to the document...
   505   nsIDocument*      mDocument;  // the document we live for
   508   // Number of datas still waiting to be notified on if we're notifying on a
   509   // whole bunch at once (e.g. in one of the stop methods).  This is used to
   510   // make sure that HasPendingLoads() won't return false until we're notifying
   511   // on the last data we're working with.
   512   uint32_t          mDatasToNotifyOn;
   514   nsCompatibility   mCompatMode;
   515   nsString          mPreferredSheet;  // title of preferred sheet
   517   bool              mEnabled; // is enabled to load new styles
   519 #ifdef DEBUG
   520   bool              mSyncCallback;
   521 #endif
   522 };
   524 } // namespace css
   525 } // namespace mozilla
   527 #endif /* mozilla_css_Loader_h */

mercurial