зеркало из https://github.com/mozilla/gecko-dev.git
Bug 503473 - Prevent document.write() in the HTML5 parser where prohibited by HTML5. r=bnewman, sr=sicking.
--HG-- extra : rebase_source : 0f574695c4d6fad936e9d0960f07261aa192b13d
This commit is contained in:
Родитель
cb2f935b80
Коммит
78c76786eb
|
@ -43,11 +43,12 @@
|
|||
#include "nsIURI.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIScriptLoaderObserver.h"
|
||||
#include "nsWeakPtr.h"
|
||||
#include "nsIParser.h"
|
||||
|
||||
// e68ddc48-4055-4ba9-978d-c49d9cf3189a
|
||||
#define NS_ISCRIPTELEMENT_IID \
|
||||
{ 0xe68ddc48, 0x4055, 0x4ba9, \
|
||||
{ 0x97, 0x8d, 0xc4, 0x9d, 0x9c, 0xf3, 0x18, 0x9a } }
|
||||
{ 0xa28c198e, 0x14f0, 0x42b1, \
|
||||
{ 0x8f, 0x6b, 0x0e, 0x7f, 0xca, 0xb4, 0xf4, 0xe8 } }
|
||||
|
||||
/**
|
||||
* Internal interface implemented by script elements
|
||||
|
@ -60,7 +61,8 @@ public:
|
|||
: mLineNumber(0),
|
||||
mIsEvaluated(PR_FALSE),
|
||||
mMalformed(PR_FALSE),
|
||||
mDoneAddingChildren(PR_TRUE)
|
||||
mDoneAddingChildren(PR_TRUE),
|
||||
mCreatorParser(nsnull)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -122,11 +124,52 @@ public:
|
|||
mDoneAddingChildren = PR_FALSE;
|
||||
}
|
||||
|
||||
void SetCreatorParser(nsIParser* aParser)
|
||||
{
|
||||
mCreatorParser = getter_AddRefs(NS_GetWeakReference(aParser));
|
||||
}
|
||||
|
||||
/**
|
||||
* Informs the creator parser that the evaluation of this script is starting
|
||||
*/
|
||||
void BeginEvaluating()
|
||||
{
|
||||
// Once the async attribute is supported, don't do this if this is an
|
||||
// async script.
|
||||
nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
|
||||
if (parser) {
|
||||
parser->BeginEvaluatingParserInsertedScript();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Informs the creator parser that the evaluation of this script is ending
|
||||
*/
|
||||
void EndEvaluating()
|
||||
{
|
||||
// Once the async attribute is supported, don't do this if this is an
|
||||
// async script.
|
||||
nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
|
||||
if (parser) {
|
||||
parser->EndEvaluatingParserInsertedScript();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a pointer to the creator parser if this has one or null if not
|
||||
*/
|
||||
already_AddRefed<nsIParser> GetCreatorParser()
|
||||
{
|
||||
nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
|
||||
return parser.forget();
|
||||
}
|
||||
|
||||
protected:
|
||||
PRUint32 mLineNumber;
|
||||
PRPackedBool mIsEvaluated;
|
||||
PRPackedBool mMalformed;
|
||||
PRPackedBool mDoneAddingChildren;
|
||||
nsWeakPtr mCreatorParser;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptElement, NS_ISCRIPTELEMENT_IID)
|
||||
|
|
|
@ -647,7 +647,9 @@ nsScriptLoader::ProcessRequest(nsScriptLoadRequest* aRequest)
|
|||
}
|
||||
|
||||
FireScriptAvailable(NS_OK, aRequest);
|
||||
aRequest->mElement->BeginEvaluating();
|
||||
nsresult rv = EvaluateScript(aRequest, *script);
|
||||
aRequest->mElement->EndEvaluating();
|
||||
FireScriptEvaluated(rv, aRequest);
|
||||
|
||||
return rv;
|
||||
|
|
|
@ -735,6 +735,7 @@ nsHTMLDocument::StartDocumentLoad(const char* aCommand,
|
|||
if (needsParser) {
|
||||
if (loadAsHtml5) {
|
||||
mParser = nsHtml5Module::NewHtml5Parser();
|
||||
mParser->MarkAsNotScriptCreated();
|
||||
} else {
|
||||
mParser = do_CreateInstance(kCParserCID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -2142,7 +2143,8 @@ nsHTMLDocument::WriteCommon(const nsAString& aText,
|
|||
void *key = GenerateParserKey();
|
||||
if (mWriteState == eDocumentClosed ||
|
||||
(mWriteState == ePendingClose &&
|
||||
!mPendingScripts.Contains(key))) {
|
||||
!mPendingScripts.Contains(key)) ||
|
||||
(mParser && !mParser->IsInsertionPointDefined())) {
|
||||
mWriteState = eDocumentClosed;
|
||||
mParser->Terminate();
|
||||
NS_ASSERTION(!mParser, "mParser should have been null'd out");
|
||||
|
@ -2935,7 +2937,21 @@ nsHTMLDocument::GenerateParserKey(void)
|
|||
|
||||
// The script loader provides us with the currently executing script element,
|
||||
// which is guaranteed to be unique per script.
|
||||
return mScriptLoader->GetCurrentScript();
|
||||
if (nsHtml5Module::sEnabled) {
|
||||
nsIScriptElement* script = mScriptLoader->GetCurrentScript();
|
||||
if (script && mParser && mParser->IsScriptCreated()) {
|
||||
nsCOMPtr<nsIParser> creatorParser = script->GetCreatorParser();
|
||||
if (creatorParser != mParser) {
|
||||
// Make scripts that aren't inserted by the active parser of this document
|
||||
// participate in the context of the script that document.open()ed
|
||||
// this document.
|
||||
return mParser->GetRootContextKey();
|
||||
}
|
||||
}
|
||||
return script;
|
||||
} else {
|
||||
return mScriptLoader->GetCurrentScript();
|
||||
}
|
||||
}
|
||||
|
||||
/* attribute DOMString designMode; */
|
||||
|
|
|
@ -85,7 +85,7 @@ public:
|
|||
|
||||
|
||||
NS_INTERFACE_TABLE_HEAD(nsHtml5Parser)
|
||||
NS_INTERFACE_TABLE1(nsHtml5Parser, nsIParser)
|
||||
NS_INTERFACE_TABLE2(nsHtml5Parser, nsIParser, nsISupportsWeakReference)
|
||||
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsHtml5Parser)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
|
@ -190,14 +190,7 @@ nsHtml5Parser::GetDTD(nsIDTD** aDTD)
|
|||
NS_IMETHODIMP
|
||||
nsHtml5Parser::GetStreamListener(nsIStreamListener** aListener)
|
||||
{
|
||||
if (!mStreamParser) {
|
||||
mStreamParser = new nsHtml5StreamParser(mExecutor, this);
|
||||
nsIDocument* doc = mExecutor->GetDocument();
|
||||
if (doc) {
|
||||
mStreamParser->SetSpeculativeLoaderWithDocument(doc);
|
||||
}
|
||||
}
|
||||
NS_ADDREF(*aListener = mStreamParser);
|
||||
NS_IF_ADDREF(*aListener = mStreamParser);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -224,6 +217,7 @@ nsHtml5Parser::ContinueInterruptedParsing()
|
|||
nsCOMPtr<nsIParser> kungFuDeathGrip(this);
|
||||
nsRefPtr<nsHtml5StreamParser> streamKungFuDeathGrip(mStreamParser);
|
||||
nsRefPtr<nsHtml5TreeOpExecutor> treeOpKungFuDeathGrip(mExecutor);
|
||||
CancelParsingEvents(); // If the executor caused us to continue, ignore event
|
||||
ParseUntilScript();
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -264,13 +258,8 @@ nsHtml5Parser::Parse(nsIURI* aURL, // legacy parameter; ignored
|
|||
*/
|
||||
NS_PRECONDITION(!mExecutor->HasStarted(),
|
||||
"Tried to start parse without initializing the parser properly.");
|
||||
if (!mStreamParser) {
|
||||
mStreamParser = new nsHtml5StreamParser(mExecutor, this);
|
||||
nsIDocument* doc = mExecutor->GetDocument();
|
||||
if (doc) {
|
||||
mStreamParser->SetSpeculativeLoaderWithDocument(doc);
|
||||
}
|
||||
}
|
||||
NS_PRECONDITION(mStreamParser,
|
||||
"Can't call this variant of Parse() on script-created parser");
|
||||
mStreamParser->SetObserver(aObserver);
|
||||
mExecutor->SetStreamParser(mStreamParser);
|
||||
mExecutor->SetParser(this);
|
||||
|
@ -319,84 +308,93 @@ nsHtml5Parser::Parse(const nsAString& aSourceBuffer,
|
|||
NS_ASSERTION(!mStreamParser,
|
||||
"Had stream parser but got document.close().");
|
||||
mDocumentClosed = PR_TRUE;
|
||||
// TODO: Try to tokenize: http://www.w3.org/Bugs/Public/show_bug.cgi?id=7917
|
||||
MaybePostContinueEvent();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_PRECONDITION(IsInsertionPointDefined(),
|
||||
"Document.write called when insertion point not defined.");
|
||||
|
||||
if (aSourceBuffer.IsEmpty()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRInt32 lineNumberSave = mTokenizer->getLineNumber();
|
||||
|
||||
if (!aSourceBuffer.IsEmpty()) {
|
||||
nsRefPtr<nsHtml5UTF16Buffer> buffer = new nsHtml5UTF16Buffer(aSourceBuffer.Length());
|
||||
memcpy(buffer->getBuffer(), aSourceBuffer.BeginReading(), aSourceBuffer.Length() * sizeof(PRUnichar));
|
||||
buffer->setEnd(aSourceBuffer.Length());
|
||||
if (!mBlocked) {
|
||||
// mExecutor->WillResume();
|
||||
while (buffer->hasMore()) {
|
||||
buffer->adjust(mLastWasCR);
|
||||
mLastWasCR = PR_FALSE;
|
||||
if (buffer->hasMore()) {
|
||||
mLastWasCR = mTokenizer->tokenizeBuffer(buffer);
|
||||
if (mTreeBuilder->HasScript()) {
|
||||
mTreeBuilder->flushCharacters(); // Flush trailing characters
|
||||
mTreeBuilder->Flush(); // Move ops to the executor
|
||||
mExecutor->Flush(); // run the ops
|
||||
}
|
||||
if (mBlocked) {
|
||||
// mExecutor->WillInterrupt();
|
||||
break;
|
||||
}
|
||||
// Ignore suspension requests
|
||||
}
|
||||
}
|
||||
}
|
||||
nsRefPtr<nsHtml5UTF16Buffer> buffer = new nsHtml5UTF16Buffer(aSourceBuffer.Length());
|
||||
memcpy(buffer->getBuffer(), aSourceBuffer.BeginReading(), aSourceBuffer.Length() * sizeof(PRUnichar));
|
||||
buffer->setEnd(aSourceBuffer.Length());
|
||||
|
||||
if (buffer->hasMore()) {
|
||||
// If we got here, the buffer wasn't parsed synchronously to completion
|
||||
// and its tail needs to go into the chain of pending buffers.
|
||||
// The script is identified by aKey. If there's nothing in the buffer
|
||||
// chain for that key, we'll insert at the head of the queue.
|
||||
// When the script leaves something in the queue, a zero-length
|
||||
// key-holder "buffer" is inserted in the queue. If the same script
|
||||
// leaves something in the chain again, it will be inserted immediately
|
||||
// before the old key holder belonging to the same script.
|
||||
nsHtml5UTF16Buffer* prevSearchBuf = nsnull;
|
||||
nsHtml5UTF16Buffer* searchBuf = mFirstBuffer;
|
||||
if (aKey) { // after document.open, the first level of document.write has null key
|
||||
while (searchBuf != mLastBuffer) {
|
||||
if (searchBuf->key == aKey) {
|
||||
// found a key holder
|
||||
// now insert the new buffer between the previous buffer
|
||||
// and the key holder.
|
||||
buffer->next = searchBuf;
|
||||
if (prevSearchBuf) {
|
||||
prevSearchBuf->next = buffer;
|
||||
} else {
|
||||
mFirstBuffer = buffer;
|
||||
}
|
||||
break;
|
||||
}
|
||||
prevSearchBuf = searchBuf;
|
||||
searchBuf = searchBuf->next;
|
||||
// The buffer is inserted to the stream here in case it won't be parsed
|
||||
// to completion.
|
||||
// The script is identified by aKey. If there's nothing in the buffer
|
||||
// chain for that key, we'll insert at the head of the queue.
|
||||
// When the script leaves something in the queue, a zero-length
|
||||
// key-holder "buffer" is inserted in the queue. If the same script
|
||||
// leaves something in the chain again, it will be inserted immediately
|
||||
// before the old key holder belonging to the same script.
|
||||
nsHtml5UTF16Buffer* prevSearchBuf = nsnull;
|
||||
nsHtml5UTF16Buffer* searchBuf = mFirstBuffer;
|
||||
if (aKey) { // after document.open, the first level of document.write has null key
|
||||
while (searchBuf != mLastBuffer) {
|
||||
if (searchBuf->key == aKey) {
|
||||
// found a key holder
|
||||
// now insert the new buffer between the previous buffer
|
||||
// and the key holder.
|
||||
buffer->next = searchBuf;
|
||||
if (prevSearchBuf) {
|
||||
prevSearchBuf->next = buffer;
|
||||
} else {
|
||||
mFirstBuffer = buffer;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (searchBuf == mLastBuffer || !aKey) {
|
||||
// key was not found or we have a first-level write after document.open
|
||||
// we'll insert to the head of the queue
|
||||
nsHtml5UTF16Buffer* keyHolder = new nsHtml5UTF16Buffer(aKey);
|
||||
keyHolder->next = mFirstBuffer;
|
||||
buffer->next = keyHolder;
|
||||
mFirstBuffer = buffer;
|
||||
}
|
||||
if (!mStreamParser) {
|
||||
MaybePostContinueEvent();
|
||||
}
|
||||
} else { // buffer didn't have more
|
||||
// Scripting semantics require a forced tree builder flush here
|
||||
mTreeBuilder->flushCharacters(); // Flush trailing characters
|
||||
mTreeBuilder->Flush(); // Move ops to the executor
|
||||
mExecutor->Flush(); // run the ops
|
||||
prevSearchBuf = searchBuf;
|
||||
searchBuf = searchBuf->next;
|
||||
}
|
||||
}
|
||||
if (searchBuf == mLastBuffer || !aKey) {
|
||||
// key was not found or we have a first-level write after document.open
|
||||
// we'll insert to the head of the queue
|
||||
nsHtml5UTF16Buffer* keyHolder = new nsHtml5UTF16Buffer(aKey);
|
||||
keyHolder->next = mFirstBuffer;
|
||||
buffer->next = keyHolder;
|
||||
mFirstBuffer = buffer;
|
||||
}
|
||||
|
||||
if (!mBlocked) {
|
||||
// mExecutor->WillResume();
|
||||
while (buffer->hasMore()) {
|
||||
buffer->adjust(mLastWasCR);
|
||||
mLastWasCR = PR_FALSE;
|
||||
if (buffer->hasMore()) {
|
||||
mLastWasCR = mTokenizer->tokenizeBuffer(buffer);
|
||||
if (mTreeBuilder->HasScript()) {
|
||||
// No need to flush characters, because an end tag was tokenized last
|
||||
mTreeBuilder->Flush(); // Move ops to the executor
|
||||
mExecutor->Flush(); // run the ops
|
||||
}
|
||||
if (mBlocked) {
|
||||
// mExecutor->WillInterrupt();
|
||||
break;
|
||||
}
|
||||
// Ignore suspension requests
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mBlocked) { // buffer was tokenized to completion
|
||||
// Scripting semantics require a forced tree builder flush here
|
||||
mTreeBuilder->flushCharacters(); // Flush trailing characters
|
||||
mTreeBuilder->Flush(); // Move ops to the executor
|
||||
mExecutor->Flush(); // run the ops
|
||||
} else if (!mStreamParser && buffer->hasMore() && aKey == mRootContextKey) {
|
||||
// The buffer wasn't parsed completely, the document was created by
|
||||
// document.open() and the script that wrote wasn't created by this parser.
|
||||
// Can't rely on the executor causing the parser to continue.
|
||||
MaybePostContinueEvent();
|
||||
}
|
||||
|
||||
mTokenizer->setLineNumber(lineNumberSave);
|
||||
return NS_OK;
|
||||
|
@ -525,6 +523,7 @@ nsHtml5Parser::Reset()
|
|||
UnblockParser();
|
||||
mDocumentClosed = PR_FALSE;
|
||||
mStreamParser = nsnull;
|
||||
mParserInsertedScriptsBeingEvaluated = 0;
|
||||
mRootContextKey = nsnull;
|
||||
mContinueEvent = nsnull; // weak ref
|
||||
mAtomTable.Clear(); // should be already cleared in the fragment case anyway
|
||||
|
@ -540,6 +539,38 @@ nsHtml5Parser::CanInterrupt()
|
|||
return !mFragmentMode;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHtml5Parser::IsInsertionPointDefined()
|
||||
{
|
||||
return !mExecutor->IsFlushing() &&
|
||||
(!mStreamParser || mParserInsertedScriptsBeingEvaluated);
|
||||
}
|
||||
|
||||
void
|
||||
nsHtml5Parser::BeginEvaluatingParserInsertedScript()
|
||||
{
|
||||
++mParserInsertedScriptsBeingEvaluated;
|
||||
}
|
||||
|
||||
void
|
||||
nsHtml5Parser::EndEvaluatingParserInsertedScript()
|
||||
{
|
||||
--mParserInsertedScriptsBeingEvaluated;
|
||||
}
|
||||
|
||||
void
|
||||
nsHtml5Parser::MarkAsNotScriptCreated()
|
||||
{
|
||||
NS_PRECONDITION(!mStreamParser, "Must not call this twice.");
|
||||
mStreamParser = new nsHtml5StreamParser(mExecutor, this);
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsHtml5Parser::IsScriptCreated()
|
||||
{
|
||||
return !mStreamParser;
|
||||
}
|
||||
|
||||
/* End nsIParser */
|
||||
|
||||
// not from interface
|
||||
|
|
|
@ -61,8 +61,11 @@
|
|||
#include "nsHtml5TreeOpExecutor.h"
|
||||
#include "nsHtml5StreamParser.h"
|
||||
#include "nsHtml5AtomTable.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
class nsHtml5Parser : public nsIParser {
|
||||
class nsHtml5Parser : public nsIParser,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
@ -250,7 +253,33 @@ class nsHtml5Parser : public nsIParser {
|
|||
* True in fragment mode and during synchronous document.write
|
||||
*/
|
||||
virtual PRBool CanInterrupt();
|
||||
|
||||
|
||||
/**
|
||||
* True if the insertion point (per HTML5) is defined.
|
||||
*/
|
||||
virtual PRBool IsInsertionPointDefined();
|
||||
|
||||
/**
|
||||
* Call immediately before starting to evaluate a parser-inserted script.
|
||||
*/
|
||||
virtual void BeginEvaluatingParserInsertedScript();
|
||||
|
||||
/**
|
||||
* Call immediately after having evaluated a parser-inserted script.
|
||||
*/
|
||||
virtual void EndEvaluatingParserInsertedScript();
|
||||
|
||||
/**
|
||||
* Marks the HTML5 parser as not a script-created parser: Prepares the
|
||||
* parser to be able to read a stream.
|
||||
*/
|
||||
virtual void MarkAsNotScriptCreated();
|
||||
|
||||
/**
|
||||
* True if this is a script-created HTML5 parser.
|
||||
*/
|
||||
virtual PRBool IsScriptCreated();
|
||||
|
||||
/* End nsIParser */
|
||||
|
||||
/**
|
||||
|
@ -318,6 +347,11 @@ class nsHtml5Parser : public nsIParser {
|
|||
*/
|
||||
PRBool mBlocked;
|
||||
|
||||
/**
|
||||
* The number of parser-inserted script currently being evaluated.
|
||||
*/
|
||||
PRInt32 mParserInsertedScriptsBeingEvaluated;
|
||||
|
||||
/**
|
||||
* True if document.close() has been called.
|
||||
*/
|
||||
|
|
|
@ -69,7 +69,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsHtml5StreamParser)
|
|||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsHtml5StreamParser)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mObserver)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRequest)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOwner)
|
||||
tmp->mOwner = nsnull;
|
||||
tmp->mExecutorFlusher = nsnull;
|
||||
tmp->mExecutor = nsnull;
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
|
||||
|
@ -79,7 +79,10 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsHtml5StreamParser)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mObserver)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRequest)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOwner)
|
||||
if (tmp->mOwner) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mOwner");
|
||||
cb.NoteXPCOMChild(static_cast<nsIParser*> (tmp->mOwner));
|
||||
}
|
||||
// hack: count the strongly owned edge wrapped in the runnable
|
||||
if (tmp->mExecutorFlusher) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mExecutorFlusher->mExecutor");
|
||||
|
|
|
@ -381,7 +381,7 @@ class nsHtml5StreamParser : public nsIStreamListener,
|
|||
/**
|
||||
* The owner parser.
|
||||
*/
|
||||
nsCOMPtr<nsHtml5Parser> mOwner;
|
||||
nsRefPtr<nsHtml5Parser> mOwner;
|
||||
|
||||
/**
|
||||
* Whether the last character tokenized was a carriage return (for CRLF)
|
||||
|
|
|
@ -268,6 +268,11 @@ nsHtml5TreeOpExecutor::Flush()
|
|||
mFlushTimer->Cancel();
|
||||
return;
|
||||
}
|
||||
if (mFlushing) {
|
||||
return;
|
||||
}
|
||||
|
||||
mFlushing = PR_TRUE;
|
||||
|
||||
nsRefPtr<nsHtml5TreeOpExecutor> kungFuDeathGrip(this); // avoid crashing near EOF
|
||||
nsCOMPtr<nsIParser> parserKungFuDeathGrip(mParser);
|
||||
|
@ -312,9 +317,12 @@ nsHtml5TreeOpExecutor::Flush()
|
|||
}
|
||||
}
|
||||
ScheduleTimer();
|
||||
|
||||
mFlushing = PR_FALSE;
|
||||
|
||||
if (mScriptElement) {
|
||||
NS_ASSERTION(!mCallDidBuildModel, "Had a script element and DidBuildModel call");
|
||||
ExecuteScript();
|
||||
RunScript();
|
||||
} else if (mCallDidBuildModel) {
|
||||
mCallDidBuildModel = PR_FALSE;
|
||||
DidBuildModel(PR_FALSE);
|
||||
|
@ -410,7 +418,7 @@ nsHtml5TreeOpExecutor::DocumentMode(nsHtml5DocumentMode m)
|
|||
* although the parser is.
|
||||
*/
|
||||
void
|
||||
nsHtml5TreeOpExecutor::ExecuteScript()
|
||||
nsHtml5TreeOpExecutor::RunScript()
|
||||
{
|
||||
mReadingFromStage = PR_FALSE;
|
||||
NS_ASSERTION(mScriptElement, "No script to run");
|
||||
|
@ -423,6 +431,7 @@ nsHtml5TreeOpExecutor::ExecuteScript()
|
|||
// calling back into mParser anymore. mParser has been nulled out by now.
|
||||
return;
|
||||
}
|
||||
sele->SetCreatorParser(mParser);
|
||||
// Notify our document that we're loading this script.
|
||||
nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(mDocument);
|
||||
NS_ASSERTION(htmlDocument, "Document didn't QI into HTML document.");
|
||||
|
@ -516,6 +525,7 @@ nsHtml5TreeOpExecutor::MaybeFlush(nsTArray<nsHtml5TreeOperation>& aOpQueue)
|
|||
void
|
||||
nsHtml5TreeOpExecutor::ForcedFlush(nsTArray<nsHtml5TreeOperation>& aOpQueue)
|
||||
{
|
||||
NS_PRECONDITION(!mFlushing, "mOpQueue modified during tree op execution.");
|
||||
if (mOpQueue.IsEmpty()) {
|
||||
mOpQueue.SwapElements(aOpQueue);
|
||||
return;
|
||||
|
|
|
@ -111,6 +111,8 @@ class nsHtml5TreeOpExecutor : public nsContentSink,
|
|||
nsCOMPtr<nsIContent> mScriptElement;
|
||||
|
||||
nsHtml5TreeOpStage mStage;
|
||||
|
||||
PRBool mFlushing;
|
||||
|
||||
/**
|
||||
* Used for deferring DidBuildModel call out of notification batch
|
||||
|
@ -315,7 +317,11 @@ class nsHtml5TreeOpExecutor : public nsContentSink,
|
|||
return mStarted;
|
||||
}
|
||||
|
||||
void ExecuteScript();
|
||||
PRBool IsFlushing() {
|
||||
return mFlushing;
|
||||
}
|
||||
|
||||
void RunScript();
|
||||
|
||||
void MaybePreventExecution() {
|
||||
if (mScriptElement) {
|
||||
|
|
|
@ -54,10 +54,9 @@
|
|||
#include "nsTArray.h"
|
||||
#include "nsIAtom.h"
|
||||
|
||||
// 506527cc-d832-420b-ba3a-80c05aa105f4
|
||||
#define NS_IPARSER_IID \
|
||||
{ 0x506527cc, 0xd832, 0x420b, \
|
||||
{ 0xba, 0x3a, 0x80, 0xc0, 0x5a, 0xa1, 0x05, 0xf4 } }
|
||||
{ 0xa44dc586, 0xc521, 0x40a1, \
|
||||
{ 0xa0, 0xaf, 0xbe, 0x02, 0xa5, 0x51, 0xe0, 0xb7 } }
|
||||
|
||||
|
||||
// {41421C60-310A-11d4-816F-000064657374}
|
||||
|
@ -300,6 +299,31 @@ class nsIParser : public nsISupports {
|
|||
* parsing for example document.write or innerHTML.
|
||||
*/
|
||||
virtual PRBool CanInterrupt() = 0;
|
||||
|
||||
/**
|
||||
* True if the insertion point (per HTML5) is defined.
|
||||
*/
|
||||
virtual PRBool IsInsertionPointDefined() = 0;
|
||||
|
||||
/**
|
||||
* Call immediately before starting to evaluate a parser-inserted script.
|
||||
*/
|
||||
virtual void BeginEvaluatingParserInsertedScript() = 0;
|
||||
|
||||
/**
|
||||
* Call immediately after having evaluated a parser-inserted script.
|
||||
*/
|
||||
virtual void EndEvaluatingParserInsertedScript() = 0;
|
||||
|
||||
/**
|
||||
* Marks the HTML5 parser as not a script-created parser.
|
||||
*/
|
||||
virtual void MarkAsNotScriptCreated() = 0;
|
||||
|
||||
/**
|
||||
* True if this is a script-created HTML5 parser.
|
||||
*/
|
||||
virtual PRBool IsScriptCreated() = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIParser, NS_IPARSER_IID)
|
||||
|
|
|
@ -1932,6 +1932,33 @@ nsParser::CanInterrupt()
|
|||
return (mFlags & NS_PARSER_FLAG_CAN_INTERRUPT) != 0;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsParser::IsInsertionPointDefined()
|
||||
{
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nsParser::BeginEvaluatingParserInsertedScript()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsParser::EndEvaluatingParserInsertedScript()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsParser::MarkAsNotScriptCreated()
|
||||
{
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsParser::IsScriptCreated()
|
||||
{
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
nsParser::SetCanInterrupt(PRBool aCanInterrupt)
|
||||
{
|
||||
|
|
|
@ -344,6 +344,31 @@ class nsParser : public nsIParser,
|
|||
*/
|
||||
virtual PRBool CanInterrupt();
|
||||
|
||||
/**
|
||||
* Return true.
|
||||
*/
|
||||
virtual PRBool IsInsertionPointDefined();
|
||||
|
||||
/**
|
||||
* No-op.
|
||||
*/
|
||||
virtual void BeginEvaluatingParserInsertedScript();
|
||||
|
||||
/**
|
||||
* No-op.
|
||||
*/
|
||||
virtual void EndEvaluatingParserInsertedScript();
|
||||
|
||||
/**
|
||||
* No-op.
|
||||
*/
|
||||
virtual void MarkAsNotScriptCreated();
|
||||
|
||||
/**
|
||||
* Always false.
|
||||
*/
|
||||
virtual PRBool IsScriptCreated();
|
||||
|
||||
/**
|
||||
* Set to parser state to indicate whether parsing tokens can be interrupted
|
||||
* @param aCanInterrupt PR_TRUE if parser can be interrupted, PR_FALSE if it can not be interrupted.
|
||||
|
|
Загрузка…
Ссылка в новой задаче