Avoid regressing bug 321781 in the HTML5 parser

This commit is contained in:
Henri Sivonen 2009-04-01 18:29:23 +03:00
parent e096617179
commit 5712cc9dc6
22 changed files with 134 additions and 7 deletions

View File

@ -4260,7 +4260,7 @@ nsDocument::GetElementsByTagName(const nsAString& aTagname,
nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aTagname);
NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY);
nsContentList *list = NS_GetContentList(this, nameAtom, GetDefaultNamespaceID()).get();
nsContentList *list = NS_GetContentList(this, nameAtom, kNameSpaceID_Unknown).get();
NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
// transfer ref to aReturn

View File

@ -85,6 +85,7 @@ CPPSRCS = \
nsHtml5ReleasableElementName.cpp \
nsHtml5MetaScanner.cpp \
nsHtml5TreeOperation.cpp \
nsHtml5StateSnapshot.cpp \
$(NULL)
FORCE_STATIC_LIB = 1

View File

@ -50,6 +50,7 @@
#include "nsHtml5HtmlAttributes.h"
#include "nsHtml5StackNode.h"
#include "nsHtml5UTF16Buffer.h"
#include "nsHtml5StateSnapshot.h"
#include "nsHtml5Portability.h"
#include "nsHtml5AttributeName.h"

View File

@ -53,6 +53,7 @@ class nsHtml5ElementName;
class nsHtml5HtmlAttributes;
class nsHtml5StackNode;
class nsHtml5UTF16Buffer;
class nsHtml5StateSnapshot;
class nsHtml5Portability;

View File

@ -50,6 +50,7 @@
#include "nsHtml5HtmlAttributes.h"
#include "nsHtml5StackNode.h"
#include "nsHtml5UTF16Buffer.h"
#include "nsHtml5StateSnapshot.h"
#include "nsHtml5Portability.h"
#include "nsHtml5ElementName.h"

View File

@ -53,6 +53,7 @@ class nsHtml5AttributeName;
class nsHtml5HtmlAttributes;
class nsHtml5StackNode;
class nsHtml5UTF16Buffer;
class nsHtml5StateSnapshot;
class nsHtml5Portability;

View File

@ -51,6 +51,7 @@
#include "nsHtml5ElementName.h"
#include "nsHtml5StackNode.h"
#include "nsHtml5UTF16Buffer.h"
#include "nsHtml5StateSnapshot.h"
#include "nsHtml5Portability.h"
#include "nsHtml5HtmlAttributes.h"

View File

@ -54,6 +54,7 @@ class nsHtml5AttributeName;
class nsHtml5ElementName;
class nsHtml5StackNode;
class nsHtml5UTF16Buffer;
class nsHtml5StateSnapshot;
class nsHtml5Portability;

View File

@ -51,6 +51,7 @@
#include "nsHtml5HtmlAttributes.h"
#include "nsHtml5StackNode.h"
#include "nsHtml5UTF16Buffer.h"
#include "nsHtml5StateSnapshot.h"
#include "nsHtml5Portability.h"
#include "nsHtml5MetaScanner.h"

View File

@ -54,6 +54,7 @@ class nsHtml5ElementName;
class nsHtml5HtmlAttributes;
class nsHtml5StackNode;
class nsHtml5UTF16Buffer;
class nsHtml5StateSnapshot;
class nsHtml5Portability;

View File

@ -166,9 +166,10 @@ nsHtml5Parser::~nsHtml5Parser()
if (mSniffingBuffer) {
delete[] mSniffingBuffer;
}
if (mMetaScanner) {
delete mMetaScanner;
}
delete mMetaScanner;
#ifdef DEBUG
delete mSnapshot;
#endif
}
NS_IMETHODIMP_(void)
@ -809,6 +810,12 @@ nsHtml5Parser::DidBuildModel()
DropParserAndPerfHint();
#ifdef DEBUG
printf("UNSAFE SCRIPTS: %d\n", sUnsafeDocWrites);
printf("TOKENIZER-SAFE SCRIPTS: %d\n", sTokenSafeDocWrites);
printf("TREEBUILDER-SAFE SCRIPTS: %d\n", sTreeSafeDocWrites);
#endif
return NS_OK;
}
@ -1182,6 +1189,21 @@ nsHtml5Parser::ParseUntilSuspend()
return;
}
// now we have a non-empty buffer
#ifdef DEBUG
if (mSnapshot && mFirstBuffer->key == GetRootContextKey()) {
if (mTokenizer->isInDataState()) {
if (mTreeBuilder->snapshotMatches(mSnapshot)) {
sTreeSafeDocWrites++;
} else {
sTokenSafeDocWrites++;
}
} else {
sUnsafeDocWrites++;
}
delete mSnapshot;
mSnapshot = nsnull;
}
#endif
mFirstBuffer->adjust(mLastWasCR);
mLastWasCR = PR_FALSE;
if (mFirstBuffer->hasMore()) {
@ -1254,6 +1276,18 @@ void
nsHtml5Parser::ExecuteScript()
{
NS_PRECONDITION(mScriptElement, "Trying to run a script without having one!");
#ifdef DEBUG
if (!mScriptsExecuting) {
NS_ASSERTION(!mSnapshot, "Already had a state snapshot");
mSnapshot = mTreeBuilder->newSnapshot();
}
#endif
nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(mScriptElement);
// 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.");
htmlDocument->ScriptLoading(sele);
// Copied from nsXMLContentSink
@ -1265,9 +1299,12 @@ nsHtml5Parser::ExecuteScript()
// If the act of insertion evaluated the script, we're fine.
// Else, block the parser till the script has loaded.
if (rv == NS_ERROR_HTMLPARSER_BLOCK) {
nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(mScriptElement);
mScriptElements.AppendObject(sele);
BlockParser();
} else {
// This may have already happened if the script executed, but in case
// it didn't then remove the element so that it doesn't get stuck forever.
htmlDocument->ScriptExecuted(sele);
}
mScriptElement = nsnull;
}
@ -1391,6 +1428,14 @@ nsHtml5Parser::FlushTags()
return NS_OK;
}
void
nsHtml5Parser::PostEvaluateScript(nsIScriptElement *aElement)
{
nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(mDocument);
NS_ASSERTION(htmlDocument, "Document didn't QI into HTML document.");
htmlDocument->ScriptExecuted(aElement);
}
void
nsHtml5Parser::ScriptExecuting()
{
@ -1404,3 +1449,8 @@ nsHtml5Parser::ScriptDidExecute()
--mScriptsExecuting;
}
#ifdef DEBUG
PRUint32 nsHtml5Parser::sUnsafeDocWrites = 0;
PRUint32 nsHtml5Parser::sTokenSafeDocWrites = 0;
PRUint32 nsHtml5Parser::sTreeSafeDocWrites = 0;
#endif

View File

@ -310,6 +310,7 @@ class nsHtml5Parser : public nsIParser,
virtual nsresult ProcessBASETag(nsIContent* aContent);
virtual void UpdateChildCounts();
virtual nsresult FlushTags();
virtual void PostEvaluateScript(nsIScriptElement *aElement);
using nsContentSink::Notify;
// Non-inherited methods
@ -343,7 +344,7 @@ class nsHtml5Parser : public nsIParser,
PRBool HasDecoder() {
return !!mUnicodeDecoder;
}
void ReadyToCallDidBuildModel() {
void ReadyToCallDidBuildModelHtml5() {
ReadyToCallDidBuildModelImpl(mTerminated);
}
private:
@ -397,6 +398,12 @@ class nsHtml5Parser : public nsIParser,
// a buffer of the size NS_HTML5_PARSER_READ_BUFFER_SIZE
nsHtml5TreeBuilder* mTreeBuilder; // manually managed strong ref
nsHtml5Tokenizer* mTokenizer; // manually managed strong ref
#ifdef DEBUG
nsHtml5StateSnapshot* mSnapshot;
static PRUint32 sUnsafeDocWrites;
static PRUint32 sTokenSafeDocWrites;
static PRUint32 sTreeSafeDocWrites;
#endif
};
#endif

View File

@ -54,6 +54,7 @@ class nsHtml5ElementName;
class nsHtml5HtmlAttributes;
class nsHtml5StackNode;
class nsHtml5UTF16Buffer;
class nsHtml5StateSnapshot;
class nsHtml5Portability

View File

@ -51,6 +51,7 @@
#include "nsHtml5ElementName.h"
#include "nsHtml5HtmlAttributes.h"
#include "nsHtml5UTF16Buffer.h"
#include "nsHtml5StateSnapshot.h"
#include "nsHtml5Portability.h"
#include "nsHtml5StackNode.h"

View File

@ -54,6 +54,7 @@ class nsHtml5AttributeName;
class nsHtml5ElementName;
class nsHtml5HtmlAttributes;
class nsHtml5UTF16Buffer;
class nsHtml5StateSnapshot;
class nsHtml5Portability;

View File

@ -53,6 +53,7 @@
#include "nsHtml5HtmlAttributes.h"
#include "nsHtml5StackNode.h"
#include "nsHtml5UTF16Buffer.h"
#include "nsHtml5StateSnapshot.h"
#include "nsHtml5Portability.h"
#include "nsHtml5Tokenizer.h"
@ -2971,6 +2972,12 @@ nsHtml5Tokenizer::getCol()
return col;
}
PRBool
nsHtml5Tokenizer::isInDataState()
{
return (stateSave == NS_HTML5TOKENIZER_DATA);
}
void
nsHtml5Tokenizer::initializeStatics()
{

View File

@ -56,6 +56,7 @@ class nsHtml5ElementName;
class nsHtml5HtmlAttributes;
class nsHtml5StackNode;
class nsHtml5UTF16Buffer;
class nsHtml5StateSnapshot;
class nsHtml5Portability;
@ -237,6 +238,7 @@ class nsHtml5Tokenizer
PRBool isPrevCR();
PRInt32 getLine();
PRInt32 getCol();
PRBool isInDataState();
static void initializeStatics();
static void releaseStatics();
};

View File

@ -47,6 +47,7 @@
#include "nsHtml5ByteReadable.h"
#include "nsHtml5TreeOperation.h"
#include "nsHtml5PendingNotification.h"
#include "nsHtml5StateSnapshot.h"
#include "nsHtml5Tokenizer.h"
#include "nsHtml5MetaScanner.h"
@ -55,6 +56,7 @@
#include "nsHtml5HtmlAttributes.h"
#include "nsHtml5StackNode.h"
#include "nsHtml5UTF16Buffer.h"
#include "nsHtml5StateSnapshot.h"
#include "nsHtml5Portability.h"
#include "nsHtml5TreeBuilder.h"
@ -3557,6 +3559,7 @@ nsHtml5TreeBuilder::flushCharacters()
if (charBufferLen > 0) {
nsHtml5StackNode* current = stack[currentPtr];
if (current->fosterParenting && charBufferContainsNonWhitespace()) {
PRInt32 eltPos = findLastOrRoot(NS_HTML5TREE_BUILDER_TABLE);
nsHtml5StackNode* node = stack[eltPos];
nsIContent* elt = node->node;
@ -3593,6 +3596,46 @@ nsHtml5TreeBuilder::charBufferContainsNonWhitespace()
return PR_FALSE;
}
nsHtml5StateSnapshot*
nsHtml5TreeBuilder::newSnapshot()
{
jArray<nsHtml5StackNode*,PRInt32> stackCopy = jArray<nsHtml5StackNode*,PRInt32>(currentPtr + 1);
for (PRInt32 i = 0; i < stackCopy.length; i++) {
(stackCopy[i] = stack[i])->retain();
}
jArray<nsHtml5StackNode*,PRInt32> listCopy = jArray<nsHtml5StackNode*,PRInt32>(listPtr + 1);
for (PRInt32 i = 0; i < listCopy.length; i++) {
nsHtml5StackNode* node = listOfActiveFormattingElements[i];
if (!!node) {
node->retain();
}
listCopy[i] = node;
}
nsHtml5Portability::retainElement(formPointer);
return new nsHtml5StateSnapshot(stackCopy, listCopy, formPointer);
}
PRBool
nsHtml5TreeBuilder::snapshotMatches(nsHtml5StateSnapshot* snapshot)
{
jArray<nsHtml5StackNode*,PRInt32> stackCopy = snapshot->stack;
jArray<nsHtml5StackNode*,PRInt32> listCopy = snapshot->listOfActiveFormattingElements;
if (stackCopy.length != currentPtr + 1 || listCopy.length != listPtr + 1 || formPointer != snapshot->formPointer) {
return PR_FALSE;
}
for (PRInt32 i = listCopy.length - 1; i >= 0; i--) {
if (listCopy[i] != listOfActiveFormattingElements[i]) {
return PR_FALSE;
}
}
for (PRInt32 i = listCopy.length - 1; i >= 0; i--) {
if (listCopy[i] != listOfActiveFormattingElements[i]) {
return PR_FALSE;
}
}
return PR_TRUE;
}
void
nsHtml5TreeBuilder::initializeStatics()
{

View File

@ -48,6 +48,7 @@
#include "nsHtml5ByteReadable.h"
#include "nsHtml5TreeOperation.h"
#include "nsHtml5PendingNotification.h"
#include "nsHtml5StateSnapshot.h"
class nsHtml5Parser;
@ -58,6 +59,7 @@ class nsHtml5ElementName;
class nsHtml5HtmlAttributes;
class nsHtml5StackNode;
class nsHtml5UTF16Buffer;
class nsHtml5StateSnapshot;
class nsHtml5Portability;
typedef nsIContent* nsIContentPtr;
@ -196,6 +198,8 @@ class nsHtml5TreeBuilder
void flushCharacters();
PRBool charBufferContainsNonWhitespace();
public:
nsHtml5StateSnapshot* newSnapshot();
PRBool snapshotMatches(nsHtml5StateSnapshot* snapshot);
static void initializeStatics();
static void releaseStatics();

View File

@ -267,7 +267,7 @@ nsHtml5TreeBuilder::end()
{
mFlushTimer->Cancel();
Flush();
mParser->ReadyToCallDidBuildModel();
mParser->ReadyToCallDidBuildModelHtml5();
#ifdef DEBUG
mActive = PR_FALSE;
#endif

View File

@ -50,6 +50,7 @@
#include "nsHtml5ElementName.h"
#include "nsHtml5HtmlAttributes.h"
#include "nsHtml5StackNode.h"
#include "nsHtml5StateSnapshot.h"
#include "nsHtml5Portability.h"
#include "nsHtml5UTF16Buffer.h"

View File

@ -53,6 +53,7 @@ class nsHtml5AttributeName;
class nsHtml5ElementName;
class nsHtml5HtmlAttributes;
class nsHtml5StackNode;
class nsHtml5StateSnapshot;
class nsHtml5Portability;