Bug 444322 - Ignore OnDataAvailable calls when we're executing a script. r+sr=bzbarsky/jst a=dveditz

git-svn-id: svn://10.0.0.236/trunk@255767 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
mrbkap%gmail.com
2009-01-08 07:40:47 +00:00
parent a5c1c31cd6
commit 070e8296b2
9 changed files with 2661 additions and 30 deletions

View File

@@ -334,6 +334,10 @@ nsContentSink::ScriptAvailable(nsresult aResult,
PRInt32 aLineNo)
{
PRUint32 count = mScriptElements.Count();
if (mParser && NS_SUCCEEDED(aResult)) {
// Only notify the parser about scripts that are actually going to run.
mParser->ScriptExecuting();
}
if (count == 0) {
return NS_OK;
@@ -385,13 +389,13 @@ nsContentSink::ScriptEvaluated(nsresult aResult,
nsIScriptElement *aElement,
PRBool aIsInline)
{
if (mParser) {
mParser->ScriptDidExecute();
}
// Check if this is the element we were waiting for
PRInt32 count = mScriptElements.Count();
if (count == 0) {
return NS_OK;
}
if (aElement != mScriptElements[count - 1]) {
if (count == 0 || aElement != mScriptElements[count - 1]) {
return NS_OK;
}
@@ -1486,14 +1490,6 @@ nsContentSink::WillBuildModelImpl()
mScrolledToRefAlready = PR_FALSE;
}
void
nsContentSink::ContinueInterruptedParsing()
{
if (mParser) {
mParser->ContinueInterruptedParsing();
}
}
void
nsContentSink::ContinueInterruptedParsingIfEnabled()
{

View File

@@ -69,7 +69,7 @@ class nsIURI;
class nsIChannel;
class nsIDocShell;
class nsICSSLoader;
class nsIParser;
class nsIParser_1_9_0_BRANCH;
class nsIAtom;
class nsIChannel;
class nsIContent;
@@ -225,10 +225,9 @@ protected:
void ContinueInterruptedParsingAsync();
void ContinueInterruptedParsingIfEnabled();
void ContinueInterruptedParsing();
nsCOMPtr<nsIDocument> mDocument;
nsCOMPtr<nsIParser> mParser;
nsCOMPtr<nsIParser_1_9_0_BRANCH>mParser;
nsCOMPtr<nsIURI> mDocumentURI;
nsCOMPtr<nsIURI> mDocumentBaseURI;
nsCOMPtr<nsIDocShell> mDocShell;

View File

@@ -189,6 +189,9 @@ _TEST_FILES = test_bug5141.html \
file_bug458248.xml^headers^ \
test_bug380418.html \
test_bug380418.html^headers^ \
test_bug444322.html \
bug444322.txt \
bug444322.js \
$(NULL)
libs:: $(_TEST_FILES)

File diff suppressed because it is too large Load Diff

View File

@@ -1852,7 +1852,7 @@ NS_IMETHODIMP
HTMLContentSink::SetParser(nsIParser* aParser)
{
NS_PRECONDITION(aParser, "Should have a parser here!");
mParser = aParser;
mParser = do_QueryInterface(aParser);
return NS_OK;
}

View File

@@ -491,7 +491,7 @@ NS_IMETHODIMP
nsXMLContentSink::SetParser(nsIParser* aParser)
{
NS_PRECONDITION(aParser, "Should have a parser here!");
mParser = aParser;
mParser = do_QueryInterface(aParser);
return NS_OK;
}

View File

@@ -58,6 +58,10 @@
{ 0x506527cc, 0xd832, 0x420b, \
{ 0xba, 0x3a, 0x80, 0xc0, 0x5a, 0xa1, 0x05, 0xf4 } }
// 5FA66227-44CF-4572-9B5F-E9A357B67ED9
#define NS_IPARSER_1_9_0_BRANCH \
{ 0x5FA66227, 0x44CF, 0x4572, \
{ 0x9B, 0x5F, 0xE9, 0xA3, 0x57, 0xB6, 0x7E, 0xD9 } }
// {41421C60-310A-11d4-816F-000064657374}
#define NS_IDEBUG_DUMP_CONTENT_IID \
@@ -291,6 +295,22 @@ class nsIParser : public nsISupports {
virtual void Reset() = 0;
};
class nsIParser_1_9_0_BRANCH : public nsIParser {
public:
/**
* Tells the parser that a script is now executing. The only data we
* should resume parsing for is document.written data. We'll deal with any
* data that comes in over the network later.
*/
virtual void ScriptExecuting() = 0;
/**
* Tells the parser that the script is done executing. We should now
* continue the regular parsing process.
*/
virtual void ScriptDidExecute() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIParser, NS_IPARSER_IID)
/* ===========================================================*

View File

@@ -281,6 +281,7 @@ nsParser::Initialize(PRBool aConstructor)
mFlags = NS_PARSER_FLAG_OBSERVERS_ENABLED |
NS_PARSER_FLAG_PARSER_ENABLED |
NS_PARSER_FLAG_CAN_TOKENIZE;
mScriptsExecuting = 0;
MOZ_TIMER_DEBUGLOG(("Reset: Parse Time: nsParser::nsParser(), this=%p\n", this));
MOZ_TIMER_RESET(mParseTime);
@@ -346,6 +347,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS(nsParser, nsIParser)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsParser)
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
NS_INTERFACE_MAP_ENTRY(nsIParser)
NS_INTERFACE_MAP_ENTRY(nsIParser_1_9_0_BRANCH)
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIParser)
NS_INTERFACE_MAP_END
@@ -1229,7 +1231,8 @@ nsParser::IsComplete()
}
void nsParser::HandleParserContinueEvent(nsParserContinueEvent *ev) {
void nsParser::HandleParserContinueEvent(nsParserContinueEvent *ev)
{
// Ignore any revoked continue events...
if (mContinueEvent != ev)
return;
@@ -1237,9 +1240,23 @@ void nsParser::HandleParserContinueEvent(nsParserContinueEvent *ev) {
mFlags &= ~NS_PARSER_FLAG_PENDING_CONTINUE_EVENT;
mContinueEvent = nsnull;
NS_ASSERTION(mScriptsExecuting == 0, "Interrupted in the middle of a script?");
ContinueInterruptedParsing();
}
void
nsParser::ScriptExecuting()
{
++mScriptsExecuting;
}
void
nsParser::ScriptDidExecute()
{
NS_ASSERTION(mScriptsExecuting > 0, "Too many calls to ScriptDidExecute");
--mScriptsExecuting;
}
nsresult
nsParser::DataAdded(const nsSubstring& aData, nsIRequest *aRequest)
{
@@ -2283,7 +2300,8 @@ nsParser::OnDataAvailable(nsIRequest *request, nsISupports* aContext,
// Don't bother to start parsing until we've seen some
// non-whitespace data
if (theContext->mScanner->FirstNonWhitespacePosition() >= 0) {
if (mScriptsExecuting == 0 &&
theContext->mScanner->FirstNonWhitespacePosition() >= 0) {
rv = ResumeParse();
}
} else {
@@ -2303,14 +2321,6 @@ nsParser::OnStopRequest(nsIRequest *request, nsISupports* aContext,
{
nsresult rv = NS_OK;
if (eOnStart == mParserContext->mStreamListenerState) {
// If you're here, then OnDataAvailable() never got called. Prior
// to necko, we never dealt with this case, but the problem may
// have existed. Everybody can live with an empty input stream, so
// just resume parsing.
rv = ResumeParse(PR_TRUE, PR_TRUE);
}
CParserContext *pc = mParserContext;
while (pc) {
if (pc->mRequest == request) {
@@ -2327,7 +2337,7 @@ nsParser::OnStopRequest(nsIRequest *request, nsISupports* aContext,
if (mParserFilter)
mParserFilter->Finish();
if (NS_SUCCEEDED(rv)) {
if (mScriptsExecuting == 0 && NS_SUCCEEDED(rv)) {
rv = ResumeParse(PR_TRUE, PR_TRUE);
}

View File

@@ -101,7 +101,7 @@ class nsIProgressEventSink;
#endif
class nsParser : public nsIParser,
class nsParser : public nsIParser_1_9_0_BRANCH,
public nsIStreamListener{
@@ -386,6 +386,19 @@ class nsParser : public nsIParser,
Initialize();
}
/**
* Tells the parser that a script is now executing. The only data we
* should resume parsing for is document.written data. We'll deal with any
* data that comes in over the network later.
*/
virtual void ScriptExecuting();
/**
* Tells the parser that the script is done executing. We should now
* continue the regular parsing process.
*/
virtual void ScriptDidExecute();
protected:
void Initialize(PRBool aConstructor = PR_FALSE);
@@ -467,6 +480,7 @@ protected:
PRInt32 mCharsetSource;
PRUint16 mFlags;
PRUint32 mScriptsExecuting;
nsString mUnusedInput;
nsCString mCharset;