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.

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

mercurial