content/base/src/nsScriptLoader.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 /*
     7  * A class that handles loading and evaluation of <script> elements.
     8  */
    10 #ifndef __nsScriptLoader_h__
    11 #define __nsScriptLoader_h__
    13 #include "nsCOMPtr.h"
    14 #include "nsIScriptElement.h"
    15 #include "nsCOMArray.h"
    16 #include "nsTArray.h"
    17 #include "nsAutoPtr.h"
    18 #include "nsIDocument.h"
    19 #include "nsIStreamLoader.h"
    21 class nsScriptLoadRequest;
    22 class nsIURI;
    24 namespace JS {
    25   class SourceBufferHolder;
    26 }
    28 //////////////////////////////////////////////////////////////
    29 // Script loader implementation
    30 //////////////////////////////////////////////////////////////
    32 class nsScriptLoader : public nsIStreamLoaderObserver
    33 {
    34   friend class nsScriptRequestProcessor;
    35 public:
    36   nsScriptLoader(nsIDocument* aDocument);
    37   virtual ~nsScriptLoader();
    39   NS_DECL_ISUPPORTS
    40   NS_DECL_NSISTREAMLOADEROBSERVER
    42   /**
    43    * The loader maintains a weak reference to the document with
    44    * which it is initialized. This call forces the reference to
    45    * be dropped.
    46    */
    47   void DropDocumentReference()
    48   {
    49     mDocument = nullptr;
    50   }
    52   /**
    53    * Add an observer for all scripts loaded through this loader.
    54    *
    55    * @param aObserver observer for all script processing.
    56    */
    57   nsresult AddObserver(nsIScriptLoaderObserver* aObserver)
    58   {
    59     return mObservers.AppendObject(aObserver) ? NS_OK :
    60       NS_ERROR_OUT_OF_MEMORY;
    61   }
    63   /**
    64    * Remove an observer.
    65    *
    66    * @param aObserver observer to be removed
    67    */
    68   void RemoveObserver(nsIScriptLoaderObserver* aObserver)
    69   {
    70     mObservers.RemoveObject(aObserver);
    71   }
    73   /**
    74    * Process a script element. This will include both loading the 
    75    * source of the element if it is not inline and evaluating
    76    * the script itself.
    77    *
    78    * If the script is an inline script that can be executed immediately
    79    * (i.e. there are no other scripts pending) then ScriptAvailable
    80    * and ScriptEvaluated will be called before the function returns.
    81    *
    82    * If true is returned the script could not be executed immediately.
    83    * In this case ScriptAvailable is guaranteed to be called at a later
    84    * point (as well as possibly ScriptEvaluated).
    85    *
    86    * @param aElement The element representing the script to be loaded and
    87    *        evaluated.
    88    */
    89   bool ProcessScriptElement(nsIScriptElement* aElement);
    91   /**
    92    * Gets the currently executing script. This is useful if you want to
    93    * generate a unique key based on the currently executing script.
    94    */
    95   nsIScriptElement* GetCurrentScript()
    96   {
    97     return mCurrentScript;
    98   }
   100   nsIScriptElement* GetCurrentParserInsertedScript()
   101   {
   102     return mCurrentParserInsertedScript;
   103   }
   105   /**
   106    * Whether the loader is enabled or not.
   107    * When disabled, processing of new script elements is disabled. 
   108    * Any call to ProcessScriptElement() will return false. Note that
   109    * this DOES NOT disable currently loading or executing scripts.
   110    */
   111   bool GetEnabled()
   112   {
   113     return mEnabled;
   114   }
   115   void SetEnabled(bool aEnabled)
   116   {
   117     if (!mEnabled && aEnabled) {
   118       ProcessPendingRequestsAsync();
   119     }
   120     mEnabled = aEnabled;
   121   }
   123   /**
   124    * Add/remove blocker. Blockers will stop scripts from executing, but not
   125    * from loading.
   126    */
   127   void AddExecuteBlocker()
   128   {
   129     ++mBlockerCount;
   130   }
   131   void RemoveExecuteBlocker()
   132   {
   133     if (!--mBlockerCount) {
   134       ProcessPendingRequestsAsync();
   135     }
   136   }
   138   /**
   139    * Convert the given buffer to a UTF-16 string.
   140    * @param aChannel     Channel corresponding to the data. May be null.
   141    * @param aData        The data to convert
   142    * @param aLength      Length of the data
   143    * @param aHintCharset Hint for the character set (e.g., from a charset
   144    *                     attribute). May be the empty string.
   145    * @param aDocument    Document which the data is loaded for. Must not be
   146    *                     null.
   147    * @param aBufOut      [out] jschar array allocated by ConvertToUTF16 and
   148    *                     containing data converted to unicode.  Caller must
   149    *                     js_free() this data when no longer needed.
   150    * @param aLengthOut   [out] Length of array returned in aBufOut in number
   151    *                     of jschars.
   152    */
   153   static nsresult ConvertToUTF16(nsIChannel* aChannel, const uint8_t* aData,
   154                                  uint32_t aLength,
   155                                  const nsAString& aHintCharset,
   156                                  nsIDocument* aDocument,
   157                                  jschar*& aBufOut, size_t& aLengthOut);
   159   /**
   160    * Processes any pending requests that are ready for processing.
   161    */
   162   void ProcessPendingRequests();
   164   /**
   165    * Check whether it's OK to load a script from aURI in
   166    * aDocument.
   167    */
   168   static nsresult ShouldLoadScript(nsIDocument* aDocument,
   169                                    nsISupports* aContext,
   170                                    nsIURI* aURI,
   171                                    const nsAString &aType);
   173   /**
   174    * Starts deferring deferred scripts and puts them in the mDeferredRequests
   175    * queue instead.
   176    */
   177   void BeginDeferringScripts()
   178   {
   179     mDeferEnabled = true;
   180     if (mDocument) {
   181       mDocument->BlockOnload();
   182     }
   183   }
   185   /**
   186    * Notifies the script loader that parsing is done.  If aTerminated is true,
   187    * this will drop any pending scripts that haven't run yet.  Otherwise, it
   188    * will stops deferring scripts and immediately processes the
   189    * mDeferredRequests queue.
   190    *
   191    * WARNING: This function will synchronously execute content scripts, so be
   192    * prepared that the world might change around you.
   193    */
   194   void ParsingComplete(bool aTerminated);
   196   /**
   197    * Returns the number of pending scripts, deferred or not.
   198    */
   199   uint32_t HasPendingOrCurrentScripts()
   200   {
   201     return mCurrentScript || mParserBlockingRequest;
   202   }
   204   /**
   205    * Adds aURI to the preload list and starts loading it.
   206    *
   207    * @param aURI The URI of the external script.
   208    * @param aCharset The charset parameter for the script.
   209    * @param aType The type parameter for the script.
   210    * @param aCrossOrigin The crossorigin attribute for the script.
   211    *                     Void if not present.
   212    * @param aScriptFromHead Whether or not the script was a child of head
   213    */
   214   virtual void PreloadURI(nsIURI *aURI, const nsAString &aCharset,
   215                           const nsAString &aType,
   216                           const nsAString &aCrossOrigin,
   217                           bool aScriptFromHead);
   219   /**
   220    * Process a request that was deferred so that the script could be compiled
   221    * off thread.
   222    */
   223   nsresult ProcessOffThreadRequest(nsScriptLoadRequest *aRequest,
   224                                    void **aOffThreadToken);
   226 private:
   227   /**
   228    * Unblocks the creator parser of the parser-blocking scripts.
   229    */
   230   void UnblockParser(nsScriptLoadRequest* aParserBlockingRequest);
   232   /**
   233    * Asynchronously resumes the creator parser of the parser-blocking scripts.
   234    */
   235   void ContinueParserAsync(nsScriptLoadRequest* aParserBlockingRequest);
   238   /**
   239    * Helper function to check the content policy for a given request.
   240    */
   241   static nsresult CheckContentPolicy(nsIDocument* aDocument,
   242                                      nsISupports *aContext,
   243                                      nsIURI *aURI,
   244                                      const nsAString &aType);
   246   /**
   247    * Start a load for aRequest's URI.
   248    */
   249   nsresult StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType,
   250                      bool aScriptFromHead);
   252   /**
   253    * Process any pending requests asynchronously (i.e. off an event) if there
   254    * are any. Note that this is a no-op if there aren't any currently pending
   255    * requests.
   256    *
   257    * This function is virtual to allow cross-library calls to SetEnabled()
   258    */
   259   virtual void ProcessPendingRequestsAsync();
   261   /**
   262    * If true, the loader is ready to execute scripts, and so are all its
   263    * ancestors.  If the loader itself is ready but some ancestor is not, this
   264    * function will add an execute blocker and ask the ancestor to remove it
   265    * once it becomes ready.
   266    */
   267   bool ReadyToExecuteScripts();
   269   /**
   270    * Return whether just this loader is ready to execute scripts.
   271    */
   272   bool SelfReadyToExecuteScripts()
   273   {
   274     return mEnabled && !mBlockerCount;
   275   }
   277   bool AddPendingChildLoader(nsScriptLoader* aChild) {
   278     return mPendingChildLoaders.AppendElement(aChild) != nullptr;
   279   }
   281   nsresult AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest);
   282   nsresult ProcessRequest(nsScriptLoadRequest* aRequest,
   283                           void **aOffThreadToken = nullptr);
   284   void FireScriptAvailable(nsresult aResult,
   285                            nsScriptLoadRequest* aRequest);
   286   void FireScriptEvaluated(nsresult aResult,
   287                            nsScriptLoadRequest* aRequest);
   288   nsresult EvaluateScript(nsScriptLoadRequest* aRequest,
   289                           JS::SourceBufferHolder& aSrcBuf,
   290                           void **aOffThreadToken);
   292   already_AddRefed<nsIScriptGlobalObject> GetScriptGlobalObject();
   293   void FillCompileOptionsForRequest(nsScriptLoadRequest *aRequest,
   294                                     JS::Handle<JSObject *> aScopeChain,
   295                                     JS::CompileOptions *aOptions);
   297   nsresult PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
   298                                 nsIStreamLoader* aLoader,
   299                                 nsresult aStatus,
   300                                 uint32_t aStringLen,
   301                                 const uint8_t* aString);
   303   void AddDeferRequest(nsScriptLoadRequest* aRequest);
   304   bool MaybeRemovedDeferRequests();
   306   nsIDocument* mDocument;                   // [WEAK]
   307   nsCOMArray<nsIScriptLoaderObserver> mObservers;
   308   nsTArray<nsRefPtr<nsScriptLoadRequest> > mNonAsyncExternalScriptInsertedRequests;
   309   nsTArray<nsRefPtr<nsScriptLoadRequest> > mAsyncRequests;
   310   nsTArray<nsRefPtr<nsScriptLoadRequest> > mDeferRequests;
   311   nsTArray<nsRefPtr<nsScriptLoadRequest> > mXSLTRequests;
   312   nsRefPtr<nsScriptLoadRequest> mParserBlockingRequest;
   314   // In mRequests, the additional information here is stored by the element.
   315   struct PreloadInfo {
   316     nsRefPtr<nsScriptLoadRequest> mRequest;
   317     nsString mCharset;
   318   };
   320   struct PreloadRequestComparator {
   321     bool Equals(const PreloadInfo &aPi, nsScriptLoadRequest * const &aRequest)
   322         const
   323     {
   324       return aRequest == aPi.mRequest;
   325     }
   326   };
   327   struct PreloadURIComparator {
   328     bool Equals(const PreloadInfo &aPi, nsIURI * const &aURI) const;
   329   };
   330   nsTArray<PreloadInfo> mPreloads;
   332   nsCOMPtr<nsIScriptElement> mCurrentScript;
   333   nsCOMPtr<nsIScriptElement> mCurrentParserInsertedScript;
   334   // XXXbz do we want to cycle-collect these or something?  Not sure.
   335   nsTArray< nsRefPtr<nsScriptLoader> > mPendingChildLoaders;
   336   uint32_t mBlockerCount;
   337   bool mEnabled;
   338   bool mDeferEnabled;
   339   bool mDocumentParsingDone;
   340   bool mBlockingDOMContentLoaded;
   341 };
   343 class nsAutoScriptLoaderDisabler
   344 {
   345 public:
   346   nsAutoScriptLoaderDisabler(nsIDocument* aDoc)
   347   {
   348     mLoader = aDoc->ScriptLoader();
   349     mWasEnabled = mLoader->GetEnabled();
   350     if (mWasEnabled) {
   351       mLoader->SetEnabled(false);
   352     }
   353   }
   355   ~nsAutoScriptLoaderDisabler()
   356   {
   357     if (mWasEnabled) {
   358       mLoader->SetEnabled(true);
   359     }
   360   }
   362   bool mWasEnabled;
   363   nsRefPtr<nsScriptLoader> mLoader;
   364 };
   366 #endif //__nsScriptLoader_h__

mercurial