зеркало из https://github.com/mozilla/gecko-dev.git
Bug 461555: Don't clear out the parser until all deferred scripts have executed to ensure that a document.write in a deferred script doesn't clear the page. r/sr=mrbkap
This commit is contained in:
Родитель
09c48cafaa
Коммит
8093e5d81b
|
@ -349,19 +349,21 @@ nsContentSink::ScriptAvailable(nsresult aResult,
|
||||||
mParser->ScriptExecuting();
|
mParser->ScriptExecuting();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count == 0) {
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// aElement will not be in mScriptElements if a <script> was added
|
// aElement will not be in mScriptElements if a <script> was added
|
||||||
// using the DOM during loading, or if the script was inline and thus
|
// using the DOM during loading, or if the script was inline and thus
|
||||||
// never blocked.
|
// never blocked.
|
||||||
NS_ASSERTION(mScriptElements.IndexOf(aElement) == PRUint32(count - 1) ||
|
NS_ASSERTION(count == 0 ||
|
||||||
|
mScriptElements.IndexOf(aElement) == PRUint32(count - 1) ||
|
||||||
mScriptElements.IndexOf(aElement) == PRUint32(-1),
|
mScriptElements.IndexOf(aElement) == PRUint32(-1),
|
||||||
"script found at unexpected position");
|
"script found at unexpected position");
|
||||||
|
|
||||||
// Check if this is the element we were waiting for
|
// Check if this is the element we were waiting for
|
||||||
if (aElement != mScriptElements[count - 1]) {
|
if (count == 0 || aElement != mScriptElements[count - 1]) {
|
||||||
|
if (mDidGetReadyToCallDidBuildModelCall &&
|
||||||
|
!mScriptLoader->HasPendingOrCurrentScripts() &&
|
||||||
|
mParser && mParser->IsParserEnabled()) {
|
||||||
|
ContinueInterruptedParsingAsync();
|
||||||
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,6 +408,11 @@ nsContentSink::ScriptEvaluated(nsresult aResult,
|
||||||
// Check if this is the element we were waiting for
|
// Check if this is the element we were waiting for
|
||||||
PRInt32 count = mScriptElements.Count();
|
PRInt32 count = mScriptElements.Count();
|
||||||
if (count == 0 || aElement != mScriptElements[count - 1]) {
|
if (count == 0 || aElement != mScriptElements[count - 1]) {
|
||||||
|
if (mDidGetReadyToCallDidBuildModelCall &&
|
||||||
|
!mScriptLoader->HasPendingOrCurrentScripts() &&
|
||||||
|
mParser && mParser->IsParserEnabled()) {
|
||||||
|
ContinueInterruptedParsingAsync();
|
||||||
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1749,6 +1756,24 @@ nsContentSink::ContinueInterruptedParsingAsync()
|
||||||
NS_DispatchToCurrentThread(ev);
|
NS_DispatchToCurrentThread(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRBool
|
||||||
|
nsContentSink::ReadyToCallDidBuildModelImpl()
|
||||||
|
{
|
||||||
|
if (!mDidGetReadyToCallDidBuildModelCall) {
|
||||||
|
if (mDocument) {
|
||||||
|
mDocument->SetReadyStateInternal(nsIDocument::READYSTATE_INTERACTIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mScriptLoader) {
|
||||||
|
mScriptLoader->EndDeferringScripts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mDidGetReadyToCallDidBuildModelCall = PR_TRUE;
|
||||||
|
|
||||||
|
return !mScriptLoader || !mScriptLoader->HasPendingOrCurrentScripts();
|
||||||
|
}
|
||||||
|
|
||||||
// URIs: action, href, src, longdesc, usemap, cite
|
// URIs: action, href, src, longdesc, usemap, cite
|
||||||
PRBool
|
PRBool
|
||||||
IsAttrURI(nsIAtom *aName)
|
IsAttrURI(nsIAtom *aName)
|
||||||
|
|
|
@ -138,6 +138,7 @@ class nsContentSink : public nsICSSLoaderObserver,
|
||||||
NS_HIDDEN_(nsresult) DidProcessATokenImpl(void);
|
NS_HIDDEN_(nsresult) DidProcessATokenImpl(void);
|
||||||
NS_HIDDEN_(void) WillBuildModelImpl(void);
|
NS_HIDDEN_(void) WillBuildModelImpl(void);
|
||||||
NS_HIDDEN_(void) DidBuildModelImpl(void);
|
NS_HIDDEN_(void) DidBuildModelImpl(void);
|
||||||
|
NS_HIDDEN_(PRBool) ReadyToCallDidBuildModelImpl(void);
|
||||||
NS_HIDDEN_(void) DropParserAndPerfHint(void);
|
NS_HIDDEN_(void) DropParserAndPerfHint(void);
|
||||||
|
|
||||||
void NotifyAppend(nsIContent* aContent, PRUint32 aStartIndex);
|
void NotifyAppend(nsIContent* aContent, PRUint32 aStartIndex);
|
||||||
|
@ -350,6 +351,8 @@ protected:
|
||||||
PRUint8 mDeferredLayoutStart : 1;
|
PRUint8 mDeferredLayoutStart : 1;
|
||||||
// If true, we deferred notifications until sheets load
|
// If true, we deferred notifications until sheets load
|
||||||
PRUint8 mDeferredFlushTags : 1;
|
PRUint8 mDeferredFlushTags : 1;
|
||||||
|
// If true, we did get a ReadyToCallDidBuildModel call
|
||||||
|
PRUint8 mDidGetReadyToCallDidBuildModelCall : 1;
|
||||||
|
|
||||||
// -- Can interrupt parsing members --
|
// -- Can interrupt parsing members --
|
||||||
PRUint32 mDelayTimerStart;
|
PRUint32 mDelayTimerStart;
|
||||||
|
|
|
@ -3966,10 +3966,6 @@ nsDocument::DispatchContentLoadedEvents()
|
||||||
} while (parent);
|
} while (parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mScriptLoader) {
|
|
||||||
mScriptLoader->EndDeferringScripts();
|
|
||||||
}
|
|
||||||
|
|
||||||
UnblockOnload(PR_TRUE);
|
UnblockOnload(PR_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3986,8 +3982,6 @@ nsDocument::EndLoad()
|
||||||
|
|
||||||
NS_DOCUMENT_NOTIFY_OBSERVERS(EndLoad, (this));
|
NS_DOCUMENT_NOTIFY_OBSERVERS(EndLoad, (this));
|
||||||
|
|
||||||
SetReadyStateInternal(READYSTATE_INTERACTIVE);
|
|
||||||
|
|
||||||
if (!mSynchronousDOMContentLoaded) {
|
if (!mSynchronousDOMContentLoaded) {
|
||||||
nsRefPtr<nsIRunnable> ev =
|
nsRefPtr<nsIRunnable> ev =
|
||||||
new nsRunnableMethod<nsDocument>(this,
|
new nsRunnableMethod<nsDocument>(this,
|
||||||
|
|
|
@ -208,6 +208,14 @@ public:
|
||||||
*/
|
*/
|
||||||
void EndDeferringScripts();
|
void EndDeferringScripts();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of pending scripts, deferred or not.
|
||||||
|
*/
|
||||||
|
PRUint32 HasPendingOrCurrentScripts()
|
||||||
|
{
|
||||||
|
return mCurrentScript || GetFirstPendingRequest();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds aURI to the preload list and starts loading it.
|
* Adds aURI to the preload list and starts loading it.
|
||||||
*
|
*
|
||||||
|
|
|
@ -282,6 +282,7 @@ _TEST_FILES = test_bug5141.html \
|
||||||
file_XHRSendData_doc.xml \
|
file_XHRSendData_doc.xml \
|
||||||
file_XHRSendData_doc.xml^headers^ \
|
file_XHRSendData_doc.xml^headers^ \
|
||||||
test_bug466751.xhtml \
|
test_bug466751.xhtml \
|
||||||
|
test_bug461555.html \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
# Disabled for now. Mochitest isn't reliable enough for these.
|
# Disabled for now. Mochitest isn't reliable enough for these.
|
||||||
|
|
|
@ -37,7 +37,7 @@ onload = function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function done() {
|
function done() {
|
||||||
is(res, "ABCDEFGHIJ1abcdefM2g34hi", "scripts executed in the wrong order");
|
is(res, "ABCDEFGHIJabcdef1M2g34hi", "scripts executed in the wrong order");
|
||||||
ok(!fHadExecuted, "Dynamic script executed too late");
|
ok(!fHadExecuted, "Dynamic script executed too late");
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=461555
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<title>Test for Bug 461555</title>
|
||||||
|
<script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||||
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=461555">Mozilla Bug 461555</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content" style="display: none">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
function writeIt(n) {
|
||||||
|
document.write("<span>" + n + "</span>");
|
||||||
|
}
|
||||||
|
|
||||||
|
var recur = 0;
|
||||||
|
function externalScript() {
|
||||||
|
if (++recur == 3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
base = (recur-1) * 4
|
||||||
|
|
||||||
|
writeIt(6 + base);
|
||||||
|
s = document.createElement("script");
|
||||||
|
s.src = "data:text/plain,writeIt(" + (8+base) + ");writeIt(" + (9+base) + ");externalScript();";
|
||||||
|
document.body.appendChild(s);
|
||||||
|
writeIt(7 + base);
|
||||||
|
}
|
||||||
|
|
||||||
|
function done() {
|
||||||
|
nodes = document.getElementsByTagName('span');
|
||||||
|
is(nodes.length, 13, "wrong length");
|
||||||
|
for (i = 0; i < nodes.length; ++i) {
|
||||||
|
is(nodes[i].textContent, i+1, "wrong order");
|
||||||
|
}
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
done();
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
writeIt(1);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<script defer>
|
||||||
|
writeIt(3);
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
writeIt(2);
|
||||||
|
</script>
|
||||||
|
<script defer src="data:text/plain,writeIt(4);writeIt(5);"></script>
|
||||||
|
<script defer src="data:text/plain,externalScript();"></script>
|
|
@ -185,6 +185,7 @@ public:
|
||||||
NS_IMETHOD WillParse(void);
|
NS_IMETHOD WillParse(void);
|
||||||
NS_IMETHOD WillBuildModel(void);
|
NS_IMETHOD WillBuildModel(void);
|
||||||
NS_IMETHOD DidBuildModel(void);
|
NS_IMETHOD DidBuildModel(void);
|
||||||
|
virtual PRBool ReadyToCallDidBuildModel(void);
|
||||||
NS_IMETHOD WillInterrupt(void);
|
NS_IMETHOD WillInterrupt(void);
|
||||||
NS_IMETHOD WillResume(void);
|
NS_IMETHOD WillResume(void);
|
||||||
NS_IMETHOD SetParser(nsIParser* aParser);
|
NS_IMETHOD SetParser(nsIParser* aParser);
|
||||||
|
@ -1837,6 +1838,12 @@ HTMLContentSink::DidBuildModel(void)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRBool
|
||||||
|
HTMLContentSink::ReadyToCallDidBuildModel()
|
||||||
|
{
|
||||||
|
return ReadyToCallDidBuildModelImpl();
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
HTMLContentSink::SetParser(nsIParser* aParser)
|
HTMLContentSink::SetParser(nsIParser* aParser)
|
||||||
{
|
{
|
||||||
|
|
|
@ -383,6 +383,12 @@ nsXMLContentSink::DidBuildModel()
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRBool
|
||||||
|
nsXMLContentSink::ReadyToCallDidBuildModel()
|
||||||
|
{
|
||||||
|
return ReadyToCallDidBuildModelImpl();
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXMLContentSink::OnDocumentCreated(nsIDocument* aResultDocument)
|
nsXMLContentSink::OnDocumentCreated(nsIDocument* aResultDocument)
|
||||||
{
|
{
|
||||||
|
|
|
@ -93,6 +93,7 @@ public:
|
||||||
NS_IMETHOD WillParse(void);
|
NS_IMETHOD WillParse(void);
|
||||||
NS_IMETHOD WillBuildModel(void);
|
NS_IMETHOD WillBuildModel(void);
|
||||||
NS_IMETHOD DidBuildModel(void);
|
NS_IMETHOD DidBuildModel(void);
|
||||||
|
virtual PRBool ReadyToCallDidBuildModel(void);
|
||||||
NS_IMETHOD WillInterrupt(void);
|
NS_IMETHOD WillInterrupt(void);
|
||||||
NS_IMETHOD WillResume(void);
|
NS_IMETHOD WillResume(void);
|
||||||
NS_IMETHOD SetParser(nsIParser* aParser);
|
NS_IMETHOD SetParser(nsIParser* aParser);
|
||||||
|
|
|
@ -56,8 +56,8 @@
|
||||||
class nsIParser;
|
class nsIParser;
|
||||||
|
|
||||||
#define NS_ICONTENT_SINK_IID \
|
#define NS_ICONTENT_SINK_IID \
|
||||||
{ 0x94ec4df1, 0x6885, 0x4b1f, \
|
{ 0xcfa3643b, 0xee60, 0x4bf0, \
|
||||||
{ 0x85, 0x10, 0xe3, 0x5f, 0x4f, 0x36, 0xea, 0xaa } }
|
{ 0xbc, 0x83, 0x49, 0x95, 0xdb, 0xbc, 0xda, 0x75 } }
|
||||||
|
|
||||||
class nsIContentSink : public nsISupports {
|
class nsIContentSink : public nsISupports {
|
||||||
public:
|
public:
|
||||||
|
@ -88,6 +88,12 @@ public:
|
||||||
*/
|
*/
|
||||||
NS_IMETHOD DidBuildModel()=0;
|
NS_IMETHOD DidBuildModel()=0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thie method gets caller right before DidBuildModel is called.
|
||||||
|
* If false
|
||||||
|
*/
|
||||||
|
virtual PRBool ReadyToCallDidBuildModel() { return PR_TRUE; };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method gets called when the parser gets i/o blocked,
|
* This method gets called when the parser gets i/o blocked,
|
||||||
* and wants to notify the sink that it may be a while before
|
* and wants to notify the sink that it may be a while before
|
||||||
|
|
|
@ -1525,7 +1525,12 @@ nsParser::DidBuildModel(nsresult anErrorCode)
|
||||||
|
|
||||||
if (IsComplete()) {
|
if (IsComplete()) {
|
||||||
if (mParserContext && !mParserContext->mPrevContext) {
|
if (mParserContext && !mParserContext->mPrevContext) {
|
||||||
if (mParserContext->mDTD) {
|
// If mInternalState == NS_ERROR_HTMLPARSER_STOPPARSING then we got in
|
||||||
|
// here through Terminate() and so we always want to Call DidBuildModel
|
||||||
|
// on the DTD, even if the sink says 'no'.
|
||||||
|
if (mParserContext->mDTD && mSink &&
|
||||||
|
(mInternalState == NS_ERROR_HTMLPARSER_STOPPARSING ||
|
||||||
|
mSink->ReadyToCallDidBuildModel())) {
|
||||||
result = mParserContext->mDTD->DidBuildModel(anErrorCode,PR_TRUE,this,mSink);
|
result = mParserContext->mDTD->DidBuildModel(anErrorCode,PR_TRUE,this,mSink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче