diff --git a/mozilla/content/base/src/nsScriptLoader.cpp b/mozilla/content/base/src/nsScriptLoader.cpp index e7ec96c9d9d..1bb68913f1c 100644 --- a/mozilla/content/base/src/nsScriptLoader.cpp +++ b/mozilla/content/base/src/nsScriptLoader.cpp @@ -171,6 +171,12 @@ nsScriptLoader::~nsScriptLoader() for (PRInt32 i = 0; i < mPendingRequests.Count(); i++) { mPendingRequests[i]->FireScriptAvailable(NS_ERROR_ABORT); } + + // Unblock the kids, in case any of them moved to a different document + // subtree in the meantime and therefore aren't actually going away. + for (PRUint32 j = 0; j < mPendingChildLoaders.Length(); ++j) { + mPendingChildLoaders[j]->RemoveExecuteBlocker(); + } } NS_IMPL_ISUPPORTS1(nsScriptLoader, nsIStreamLoaderObserver) @@ -636,7 +642,7 @@ nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest, void nsScriptLoader::ProcessPendingRequestsAsync() { - if (mPendingRequests.Count()) { + if (mPendingRequests.Count() || !mPendingChildLoaders.IsEmpty()) { nsCOMPtr ev = new nsRunnableMethod(this, &nsScriptLoader::ProcessPendingRequests); @@ -653,6 +659,33 @@ nsScriptLoader::ProcessPendingRequests() mPendingRequests.RemoveObjectAt(0); ProcessRequest(request); } + + while (ReadyToExecuteScripts() && !mPendingChildLoaders.IsEmpty()) { + nsRefPtr child = mPendingChildLoaders[0]; + mPendingChildLoaders.RemoveElementAt(0); + child->RemoveExecuteBlocker(); + } +} + +PRBool +nsScriptLoader::ReadyToExecuteScripts() +{ + // Make sure the SelfReadyToExecuteScripts check is first, so that + // we don't block twice on an ancestor. + if (!SelfReadyToExecuteScripts()) { + return PR_FALSE; + } + + for (nsIDocument* doc = mDocument; doc; doc = doc->GetParentDocument()) { + nsScriptLoader* ancestor = doc->ScriptLoader(); + if (!ancestor->SelfReadyToExecuteScripts() && + ancestor->AddPendingChildLoader(this)) { + AddExecuteBlocker(); + return PR_FALSE; + } + } + + return PR_TRUE; } diff --git a/mozilla/content/base/src/nsScriptLoader.h b/mozilla/content/base/src/nsScriptLoader.h index 5f3efc71c94..58d855675b4 100644 --- a/mozilla/content/base/src/nsScriptLoader.h +++ b/mozilla/content/base/src/nsScriptLoader.h @@ -47,6 +47,8 @@ #include "nsIScriptElement.h" #include "nsIURI.h" #include "nsCOMArray.h" +#include "nsTArray.h" +#include "nsAutoPtr.h" #include "nsIDocument.h" #include "nsIStreamLoader.h" @@ -202,11 +204,26 @@ protected: */ virtual void ProcessPendingRequestsAsync(); - PRBool ReadyToExecuteScripts() + /** + * If true, the loader is ready to execute scripts, and so are all its + * ancestors. If the loader itself is ready but some ancestor is not, this + * function will add an execute blocker and ask the ancestor to remove it + * once it becomes ready. + */ + PRBool ReadyToExecuteScripts(); + + /** + * Return whether just this loader is ready to execute scripts. + */ + PRBool SelfReadyToExecuteScripts() { return mEnabled && !mBlockerCount; } + PRBool AddPendingChildLoader(nsScriptLoader* aChild) { + return mPendingChildLoaders.AppendElement(aChild) != nsnull; + } + nsresult ProcessRequest(nsScriptLoadRequest* aRequest); void FireScriptAvailable(nsresult aResult, nsScriptLoadRequest* aRequest); @@ -225,6 +242,8 @@ protected: nsCOMArray mObservers; nsCOMArray mPendingRequests; nsCOMPtr mCurrentScript; + // XXXbz do we want to cycle-collect these or something? Not sure. + nsTArray< nsRefPtr > mPendingChildLoaders; PRUint32 mBlockerCount; PRPackedBool mEnabled; PRPackedBool mHadPendingScripts;