зеркало из https://github.com/mozilla/gecko-dev.git
Bug 371576: Execute scripts syncronously when inserted in the tree whenever possible. r/sr=bz
This commit is contained in:
Родитель
67c697f0d1
Коммит
25f98dc2f4
|
@ -41,7 +41,7 @@
|
|||
interface nsIScriptElement;
|
||||
interface nsIURI;
|
||||
|
||||
[scriptable, uuid(501209d3-7edf-437d-9948-3c6d1c08ef7f)]
|
||||
[scriptable, uuid(7b787204-76fb-4764-96f1-fb7a666db4f4)]
|
||||
interface nsIScriptLoaderObserver : nsISupports {
|
||||
|
||||
/**
|
||||
|
@ -54,10 +54,6 @@ interface nsIScriptLoaderObserver : nsISupports {
|
|||
* will not occur.
|
||||
* @param aElement The element being processed.
|
||||
* @param aIsInline Is this an inline script or externally loaded?
|
||||
* @param aWasPending Did script processing have to be delayed,
|
||||
* either for loading of an external script or
|
||||
* because processing of an earlier scheduled
|
||||
* script was delayed?
|
||||
* @param aURI What is the URI of the script (the document URI if
|
||||
* it is inline).
|
||||
* @param aLineNo At what line does the script appear (generally 1
|
||||
|
@ -66,7 +62,6 @@ interface nsIScriptLoaderObserver : nsISupports {
|
|||
void scriptAvailable(in nsresult aResult,
|
||||
in nsIScriptElement aElement,
|
||||
in boolean aIsInline,
|
||||
in boolean aWasPending,
|
||||
in nsIURI aURI,
|
||||
in PRInt32 aLineNo);
|
||||
|
||||
|
@ -77,14 +72,9 @@ interface nsIScriptLoaderObserver : nsISupports {
|
|||
* the script evaluation.
|
||||
* @param aElement The element being processed.
|
||||
* @param aIsInline Is this an inline script or externally loaded?
|
||||
* @param aWasPending Did script processing have to be delayed,
|
||||
* either for loading of an external script or
|
||||
* because processing of an earlier scheduled
|
||||
* script was delayed?
|
||||
*/
|
||||
void scriptEvaluated(in nsresult aResult,
|
||||
in nsIScriptElement aElement,
|
||||
in boolean aIsInline,
|
||||
in boolean aWasPending);
|
||||
in boolean aIsInline);
|
||||
|
||||
};
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
#include "nsIRequest.h"
|
||||
#include "nsNodeUtils.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
PRLogModuleInfo* gContentSinkLogModuleInfo;
|
||||
|
||||
|
@ -117,15 +118,14 @@ NS_IMETHODIMP
|
|||
nsScriptLoaderObserverProxy::ScriptAvailable(nsresult aResult,
|
||||
nsIScriptElement *aElement,
|
||||
PRBool aIsInline,
|
||||
PRBool aWasPending,
|
||||
nsIURI *aURI,
|
||||
PRInt32 aLineNo)
|
||||
{
|
||||
nsCOMPtr<nsIScriptLoaderObserver> inner = do_QueryReferent(mInner);
|
||||
|
||||
if (inner) {
|
||||
return inner->ScriptAvailable(aResult, aElement, aIsInline, aWasPending,
|
||||
aURI, aLineNo);
|
||||
return inner->ScriptAvailable(aResult, aElement, aIsInline, aURI,
|
||||
aLineNo);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -134,13 +134,12 @@ nsScriptLoaderObserverProxy::ScriptAvailable(nsresult aResult,
|
|||
NS_IMETHODIMP
|
||||
nsScriptLoaderObserverProxy::ScriptEvaluated(nsresult aResult,
|
||||
nsIScriptElement *aElement,
|
||||
PRBool aIsInline,
|
||||
PRBool aWasPending)
|
||||
PRBool aIsInline)
|
||||
{
|
||||
nsCOMPtr<nsIScriptLoaderObserver> inner = do_QueryReferent(mInner);
|
||||
|
||||
if (inner) {
|
||||
return inner->ScriptEvaluated(aResult, aElement, aIsInline, aWasPending);
|
||||
return inner->ScriptEvaluated(aResult, aElement, aIsInline);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -273,7 +272,6 @@ NS_IMETHODIMP
|
|||
nsContentSink::ScriptAvailable(nsresult aResult,
|
||||
nsIScriptElement *aElement,
|
||||
PRBool aIsInline,
|
||||
PRBool aWasPending,
|
||||
nsIURI *aURI,
|
||||
PRInt32 aLineNo)
|
||||
{
|
||||
|
@ -308,7 +306,7 @@ nsContentSink::ScriptAvailable(nsresult aResult,
|
|||
} else {
|
||||
mScriptElements.RemoveObjectAt(count - 1);
|
||||
|
||||
if (mParser && aWasPending && aResult != NS_BINDING_ABORTED) {
|
||||
if (mParser && aResult != NS_BINDING_ABORTED) {
|
||||
// Loading external script failed!. So, resume parsing since the parser
|
||||
// got blocked when loading external script. See
|
||||
// http://bugzilla.mozilla.org/show_bug.cgi?id=94903.
|
||||
|
@ -317,7 +315,7 @@ nsContentSink::ScriptAvailable(nsresult aResult,
|
|||
// script load, assuming that that error code means that the user
|
||||
// stopped the load through some action (like clicking a link). See
|
||||
// http://bugzilla.mozilla.org/show_bug.cgi?id=243392.
|
||||
mParser->ContinueInterruptedParsing();
|
||||
ContinueInterruptedParsingAsync();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -327,8 +325,7 @@ nsContentSink::ScriptAvailable(nsresult aResult,
|
|||
NS_IMETHODIMP
|
||||
nsContentSink::ScriptEvaluated(nsresult aResult,
|
||||
nsIScriptElement *aElement,
|
||||
PRBool aIsInline,
|
||||
PRBool aWasPending)
|
||||
PRBool aIsInline)
|
||||
{
|
||||
// Check if this is the element we were waiting for
|
||||
PRInt32 count = mScriptElements.Count();
|
||||
|
@ -347,8 +344,8 @@ nsContentSink::ScriptEvaluated(nsresult aResult,
|
|||
PostEvaluateScript(aElement);
|
||||
}
|
||||
|
||||
if (mParser && mParser->IsParserEnabled() && aWasPending) {
|
||||
mParser->ContinueInterruptedParsing();
|
||||
if (mParser && mParser->IsParserEnabled()) {
|
||||
ContinueInterruptedParsingAsync();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -1350,3 +1347,20 @@ nsContentSink::WillBuildModelImpl()
|
|||
|
||||
mScrolledToRefAlready = PR_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
nsContentSink::ContinueInterruptedParsing()
|
||||
{
|
||||
if (mParser) {
|
||||
mParser->ContinueInterruptedParsing();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsContentSink::ContinueInterruptedParsingAsync()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> ev = new nsRunnableMethod<nsContentSink>(this,
|
||||
&nsContentSink::ContinueInterruptedParsing);
|
||||
|
||||
NS_DispatchToCurrentThread(ev);
|
||||
}
|
||||
|
|
|
@ -209,6 +209,9 @@ private:
|
|||
|
||||
protected:
|
||||
|
||||
void ContinueInterruptedParsingAsync();
|
||||
void ContinueInterruptedParsing();
|
||||
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
nsCOMPtr<nsIParser> mParser;
|
||||
nsCOMPtr<nsIURI> mDocumentURI;
|
||||
|
|
|
@ -66,7 +66,6 @@ NS_IMETHODIMP
|
|||
nsScriptElement::ScriptAvailable(nsresult aResult,
|
||||
nsIScriptElement *aElement,
|
||||
PRBool aIsInline,
|
||||
PRBool aWasPending,
|
||||
nsIURI *aURI,
|
||||
PRInt32 aLineNo)
|
||||
{
|
||||
|
@ -99,8 +98,7 @@ nsScriptElement::ScriptAvailable(nsresult aResult,
|
|||
NS_IMETHODIMP
|
||||
nsScriptElement::ScriptEvaluated(nsresult aResult,
|
||||
nsIScriptElement *aElement,
|
||||
PRBool aIsInline,
|
||||
PRBool aWasPending)
|
||||
PRBool aIsInline)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
if (!aIsInline) {
|
||||
|
|
|
@ -121,7 +121,7 @@ public:
|
|||
nsScriptLoadRequest(nsIScriptElement* aElement,
|
||||
PRUint32 aVersion)
|
||||
: mElement(aElement),
|
||||
mLoading(PR_TRUE), mWasPending(PR_FALSE),
|
||||
mLoading(PR_TRUE),
|
||||
mIsInline(PR_TRUE),
|
||||
mJSVersion(aVersion), mLineNo(1)
|
||||
{
|
||||
|
@ -131,17 +131,15 @@ public:
|
|||
|
||||
void FireScriptAvailable(nsresult aResult)
|
||||
{
|
||||
mElement->ScriptAvailable(aResult, mElement, mIsInline, mWasPending,
|
||||
mURI, mLineNo);
|
||||
mElement->ScriptAvailable(aResult, mElement, mIsInline, mURI, mLineNo);
|
||||
}
|
||||
void FireScriptEvaluated(nsresult aResult)
|
||||
{
|
||||
mElement->ScriptEvaluated(aResult, mElement, mIsInline, mWasPending);
|
||||
mElement->ScriptEvaluated(aResult, mElement, mIsInline);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptElement> mElement;
|
||||
PRPackedBool mLoading; // Are we still waiting for a load to complete?
|
||||
PRPackedBool mWasPending; // Processed immediately or pending
|
||||
PRPackedBool mIsInline; // Is the script inline or loaded?
|
||||
nsString mScriptText; // Holds script for loaded scripts
|
||||
PRUint32 mJSVersion;
|
||||
|
@ -161,7 +159,8 @@ NS_IMPL_THREADSAFE_ISUPPORTS0(nsScriptLoadRequest)
|
|||
nsScriptLoader::nsScriptLoader(nsIDocument *aDocument)
|
||||
: mDocument(aDocument),
|
||||
mBlockerCount(0),
|
||||
mEnabled(PR_TRUE)
|
||||
mEnabled(PR_TRUE),
|
||||
mHadPendingScripts(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -226,7 +225,6 @@ IsScriptEventHandler(nsIScriptElement *aScriptElement)
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
/* void processScriptElement (in nsIScriptElement aElement, in nsIScriptLoaderObserver aObserver); */
|
||||
nsresult
|
||||
nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
||||
{
|
||||
|
@ -445,7 +443,6 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||
|
||||
request->mURI = scriptURI;
|
||||
request->mIsInline = PR_FALSE;
|
||||
request->mWasPending = PR_TRUE;
|
||||
request->mLoading = PR_TRUE;
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = mDocument->GetDocumentLoadGroup();
|
||||
|
@ -487,11 +484,8 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
|
|||
// If we've got existing pending requests, add ourselves
|
||||
// to this list.
|
||||
if (ReadyToExecuteScripts() && mPendingRequests.Count() == 0) {
|
||||
NS_ASSERTION(!request->mWasPending, "should not be pending");
|
||||
return ProcessRequest(request);
|
||||
}
|
||||
|
||||
request->mWasPending = PR_TRUE;
|
||||
}
|
||||
|
||||
// Add the request to our pending requests list
|
||||
|
@ -538,8 +532,8 @@ nsScriptLoader::FireScriptAvailable(nsresult aResult,
|
|||
for (PRInt32 i = 0; i < mObservers.Count(); i++) {
|
||||
nsCOMPtr<nsIScriptLoaderObserver> obs = mObservers[i];
|
||||
obs->ScriptAvailable(aResult, aRequest->mElement,
|
||||
aRequest->mIsInline, aRequest->mWasPending,
|
||||
aRequest->mURI, aRequest->mLineNo);
|
||||
aRequest->mIsInline, aRequest->mURI,
|
||||
aRequest->mLineNo);
|
||||
}
|
||||
|
||||
aRequest->FireScriptAvailable(aResult);
|
||||
|
@ -552,7 +546,7 @@ nsScriptLoader::FireScriptEvaluated(nsresult aResult,
|
|||
for (PRInt32 i = 0; i < mObservers.Count(); i++) {
|
||||
nsCOMPtr<nsIScriptLoaderObserver> obs = mObservers[i];
|
||||
obs->ScriptEvaluated(aResult, aRequest->mElement,
|
||||
aRequest->mIsInline, aRequest->mWasPending);
|
||||
aRequest->mIsInline);
|
||||
}
|
||||
|
||||
aRequest->FireScriptEvaluated(aResult);
|
||||
|
|
|
@ -151,12 +151,25 @@ public:
|
|||
*/
|
||||
void AddExecuteBlocker()
|
||||
{
|
||||
++mBlockerCount;
|
||||
if (!mBlockerCount++) {
|
||||
mHadPendingScripts = mPendingRequests.Count() != 0;
|
||||
}
|
||||
}
|
||||
void RemoveExecuteBlocker()
|
||||
{
|
||||
if (!--mBlockerCount) {
|
||||
ProcessPendingRequestsAsync();
|
||||
// If there were pending scripts then the newly added scripts will
|
||||
// execute once whatever event triggers the pending scripts fires.
|
||||
// However, due to syncronous loads and pushed event queues it's
|
||||
// possible that the requests that were there have already been processed
|
||||
// if so we need to process any new requests asyncronously.
|
||||
// Ideally that should be fixed such that it can't happen.
|
||||
if (mHadPendingScripts) {
|
||||
ProcessPendingRequestsAsync();
|
||||
}
|
||||
else {
|
||||
ProcessPendingRequests();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,6 +227,7 @@ protected:
|
|||
nsCOMPtr<nsIScriptElement> mCurrentScript;
|
||||
PRUint32 mBlockerCount;
|
||||
PRPackedBool mEnabled;
|
||||
PRPackedBool mHadPendingScripts;
|
||||
};
|
||||
|
||||
#endif //__nsScriptLoader_h__
|
||||
|
|
|
@ -849,6 +849,10 @@ nsGenericHTMLElement::GetInnerHTML(nsAString& aInnerHTML)
|
|||
nsresult
|
||||
nsGenericHTMLElement::SetInnerHTML(const nsAString& aInnerHTML)
|
||||
{
|
||||
// This BeginUpdate/EndUpdate pair is important to make us reenable the
|
||||
// scriptloader before the last EndUpdate call.
|
||||
mozAutoDocUpdate updateBatch(GetCurrentDoc(), UPDATE_CONTENT_MODEL, PR_TRUE);
|
||||
|
||||
// Remove childnodes
|
||||
nsContentUtils::SetNodeTextContent(this, EmptyString(), PR_FALSE);
|
||||
|
||||
|
|
|
@ -18,8 +18,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=300691
|
|||
<pre id="test">
|
||||
<script type="text/javascript">
|
||||
// First, setup. We'll be toggling these variables as we go.
|
||||
// Note that scripts don't execute immediately when you put text in them --
|
||||
// they wait for the currently-running script to finish.
|
||||
var test1Ran = false;
|
||||
var test2Ran = false;
|
||||
var test3Ran = false;
|
||||
|
@ -61,17 +59,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=300691
|
|||
<script class="testbody" type="text/javascript">
|
||||
/** Test for Bug 300691 **/
|
||||
$("test2").appendChild(document.createTextNode("test2Ran = true"));
|
||||
is(test2Ran, false, "Not yet 2!");
|
||||
is(test2Ran, true, "Should be 2!");
|
||||
|
||||
$("test3").appendChild(document.createTextNode("test3Ran = true"));
|
||||
is(test3Ran, false, "Not yet 3!");
|
||||
is(test3Ran, false, "Should have run already 3!");
|
||||
|
||||
$("test4").appendChild(document.createTextNode("test4Ran = true"));
|
||||
is(test4Ran, false, "Not yet 4!");
|
||||
is(test4Ran, false, "Should have run already 4!");
|
||||
|
||||
$("test5").appendChild(document.createTextNode(" "));
|
||||
$("test5").appendChild(document.createTextNode("test5Ran = true"));
|
||||
is(test5Ran, false, "Not yet 5!");
|
||||
is(test5Ran, false, "Should have run already 5!");
|
||||
|
||||
$("test6").appendChild(document.createTextNode(" "));
|
||||
|
||||
|
@ -101,31 +99,27 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=300691
|
|||
<script type="text/javascript">
|
||||
// Follow up on some of those
|
||||
$("test6").appendChild(document.createTextNode("test6Ran = true"));
|
||||
is(test6Ran, false, "Not yet 6!");
|
||||
is(test6Ran, false, "Should have run already 6!");
|
||||
|
||||
$("test7").appendChild(document.createTextNode("test7Ran = true"));
|
||||
is(test7Ran, false, "Not yet 7!");
|
||||
is(test7Ran, true, "Should be 7!");
|
||||
|
||||
$("test8").insertBefore(document.createTextNode("test8Ran = true"),
|
||||
$("test8").firstChild);
|
||||
is(test8Ran, false, "Not yet 8!");
|
||||
is(test8Ran, true, "Should be 8!");
|
||||
|
||||
$("test9").firstChild.data = "test9Ran = true";
|
||||
is(test9Ran, false, "Not yet 9!");
|
||||
is(test9Ran, true, "Should be 9!");
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
is(test1Ran, true, "Should have run!");
|
||||
is(test2Ran, true, "Should execute empty script on child append");
|
||||
is(test3Ran, false, "Already executed test3 script once");
|
||||
is(test4Ran, false,
|
||||
"Shouldn't execute whitespace-only script on child append; should have executed it before");
|
||||
is(test5Ran, true,
|
||||
"By the time it tries to execute, it's got both textnodes");
|
||||
"Should have executed whitespace-only script already");
|
||||
is(test5Ran, false,
|
||||
"Should have executed once the whitespace node was added");
|
||||
is(test6Ran, false,
|
||||
"Shouldn't execute whitespace-only script on child append 2; should have executed it when it became nonempty");
|
||||
is(test7Ran, true, "Should execute empty script on child append 2");
|
||||
is(test8Ran, true, "Should execute empty script on child insert");
|
||||
is(test9Ran, true, "Should execute empty script if child gets some text");
|
||||
"Should have executed once the whitespace node was added 2");
|
||||
is(test10Ran, false, "Has an src; inline part shouldn't run");
|
||||
is(test11Ran, true, "Script with src should have run");
|
||||
is(test12Ran, true, "Setting src should execute script");
|
||||
|
|
|
@ -30,7 +30,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=300691
|
|||
<![CDATA[
|
||||
/** Test for Bug 300691 **/
|
||||
$("test2").appendChild(document.createCDATASection("test2Ran = true"));
|
||||
is(test2Ran, false, "Not yet 2!");
|
||||
is(test2Ran, true, "Should be 2!");
|
||||
|
||||
$("test3").appendChild(document.createCDATASection(""));
|
||||
]]>
|
||||
|
@ -38,12 +38,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=300691
|
|||
<script type="text/javascript">
|
||||
// Follow up on some of those
|
||||
$("test3").firstChild.data = "test3Ran = true";
|
||||
is(test3Ran, false, "Not yet 3!");
|
||||
is(test3Ran, true, "Should be 3!");
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
is(test1Ran, true, "Should have run!");
|
||||
is(test2Ran, true, "Should execute empty script on child append");
|
||||
is(test3Ran, true, "Should execute empty script if child gets some text");
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -1020,7 +1020,6 @@ NS_IMETHODIMP
|
|||
txTransformNotifier::ScriptAvailable(nsresult aResult,
|
||||
nsIScriptElement *aElement,
|
||||
PRBool aIsInline,
|
||||
PRBool aWasPending,
|
||||
nsIURI *aURI,
|
||||
PRInt32 aLineNo)
|
||||
{
|
||||
|
@ -1035,8 +1034,7 @@ txTransformNotifier::ScriptAvailable(nsresult aResult,
|
|||
NS_IMETHODIMP
|
||||
txTransformNotifier::ScriptEvaluated(nsresult aResult,
|
||||
nsIScriptElement *aElement,
|
||||
PRBool aIsInline,
|
||||
PRBool aWasPending)
|
||||
PRBool aIsInline)
|
||||
{
|
||||
if (mScriptElements.RemoveObject(aElement)) {
|
||||
SignalTransformEnd();
|
||||
|
|
Загрузка…
Ссылка в новой задаче