Bug 483015 - Expose HTML line number to JS and CSS parsers in the HTML5 parser. r=bnewman, a=beltzner.

This commit is contained in:
Henri Sivonen 2009-10-28 15:48:37 +02:00
Родитель 75191b2cf1
Коммит 2b0cb4fef4
11 изменённых файлов: 123 добавлений и 19 удалений

Просмотреть файл

@ -87,6 +87,7 @@ nsHtml5Parser::nsHtml5Parser()
, mExecutor(new nsHtml5TreeOpExecutor())
, mTreeBuilder(new nsHtml5TreeBuilder(mExecutor))
, mTokenizer(new nsHtml5Tokenizer(mTreeBuilder))
, mRootContextLineNumber(1)
{
mAtomTable.Init(); // we aren't checking for OOM anyway...
mTokenizer->setInterner(&mAtomTable);
@ -293,12 +294,12 @@ nsHtml5Parser::Parse(const nsAString& aSourceBuffer,
NS_PRECONDITION(IsInsertionPointDefined(),
"Document.write called when insertion point not defined.");
NS_PRECONDITION(!(mStreamParser && !aKey), "Got a null key in a non-script-created parser");
if (aSourceBuffer.IsEmpty()) {
return NS_OK;
}
PRInt32 lineNumberSave = mTokenizer->getLineNumber();
nsRefPtr<nsHtml5UTF16Buffer> buffer = new nsHtml5UTF16Buffer(aSourceBuffer.Length());
memcpy(buffer->getBuffer(), aSourceBuffer.BeginReading(), aSourceBuffer.Length() * sizeof(PRUnichar));
buffer->setEnd(aSourceBuffer.Length());
@ -346,7 +347,25 @@ nsHtml5Parser::Parse(const nsAString& aSourceBuffer,
buffer->adjust(mLastWasCR);
mLastWasCR = PR_FALSE;
if (buffer->hasMore()) {
PRInt32 lineNumberSave;
PRBool inRootContext = (!mStreamParser && (aKey == mRootContextKey));
if (inRootContext) {
mTokenizer->setLineNumber(mRootContextLineNumber);
} else {
// we aren't the root context, so save the line number on the
// *stack* so that we can restore it.
lineNumberSave = mTokenizer->getLineNumber();
}
mLastWasCR = mTokenizer->tokenizeBuffer(buffer);
if (inRootContext) {
mRootContextLineNumber = mTokenizer->getLineNumber();
} else {
mTokenizer->setLineNumber(lineNumberSave);
}
if (mTreeBuilder->HasScript()) {
// No need to flush characters, because an end tag was tokenized last
mTreeBuilder->Flush(); // Move ops to the executor
@ -362,13 +381,13 @@ nsHtml5Parser::Parse(const nsAString& aSourceBuffer,
}
if (!mBlocked) { // buffer was tokenized to completion
NS_ASSERTION(!buffer->hasMore(), "Buffer wasn't 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
}
mTokenizer->setLineNumber(lineNumberSave);
return NS_OK;
}
@ -492,6 +511,7 @@ nsHtml5Parser::Reset()
UnblockParser();
mDocumentClosed = PR_FALSE;
mStreamParser = nsnull;
mRootContextLineNumber = 1;
mParserInsertedScriptsBeingEvaluated = 0;
mRootContextKey = nsnull;
mAtomTable.Clear(); // should be already cleared in the fragment case anyway
@ -603,7 +623,14 @@ nsHtml5Parser::ParseUntilBlocked()
mFirstBuffer->adjust(mLastWasCR);
mLastWasCR = PR_FALSE;
if (mFirstBuffer->hasMore()) {
PRBool inRootContext = (!mStreamParser && (mFirstBuffer->key == mRootContextKey));
if (inRootContext) {
mTokenizer->setLineNumber(mRootContextLineNumber);
}
mLastWasCR = mTokenizer->tokenizeBuffer(mFirstBuffer);
if (inRootContext) {
mRootContextLineNumber = mTokenizer->getLineNumber();
}
if (mTreeBuilder->HasScript()) {
mTreeBuilder->Flush();
mExecutor->Flush();
@ -636,9 +663,10 @@ nsHtml5Parser::StartTokenizer(PRBool aScriptingEnabled) {
}
void
nsHtml5Parser::InitializeDocWriteParserState(nsAHtml5TreeBuilderState* aState)
nsHtml5Parser::InitializeDocWriteParserState(nsAHtml5TreeBuilderState* aState, PRInt32 aLine)
{
mTokenizer->resetToDataState();
mTokenizer->setLineNumber(aLine);
mTreeBuilder->loadState(aState, &mAtomTable);
mLastWasCR = PR_FALSE;
mReturnToStreamParserPermitted = PR_TRUE;

Просмотреть файл

@ -294,7 +294,7 @@ class nsHtml5Parser : public nsIParser,
return mTokenizer;
}
void InitializeDocWriteParserState(nsAHtml5TreeBuilderState* aState);
void InitializeDocWriteParserState(nsAHtml5TreeBuilderState* aState, PRInt32 aLine);
void DropStreamParser() {
mStreamParser = nsnull;
@ -378,6 +378,11 @@ class nsHtml5Parser : public nsIParser,
* The stream parser.
*/
nsRefPtr<nsHtml5StreamParser> mStreamParser;
/**
*
*/
PRInt32 mRootContextLineNumber;
/**
* Whether it's OK to transfer parsing back to the stream parser

Просмотреть файл

@ -39,9 +39,11 @@
nsHtml5Speculation::nsHtml5Speculation(nsHtml5UTF16Buffer* aBuffer,
PRInt32 aStart,
PRInt32 aStartLineNumber,
nsAHtml5TreeBuilderState* aSnapshot)
: mBuffer(aBuffer)
, mStart(aStart)
, mStartLineNumber(aStartLineNumber)
, mSnapshot(aSnapshot)
{
MOZ_COUNT_CTOR(nsHtml5Speculation);

Просмотреть файл

@ -50,6 +50,7 @@ class nsHtml5Speculation : public nsAHtml5TreeOpSink
public:
nsHtml5Speculation(nsHtml5UTF16Buffer* aBuffer,
PRInt32 aStart,
PRInt32 aStartLineNumber,
nsAHtml5TreeBuilderState* aSnapshot);
~nsHtml5Speculation();
@ -61,6 +62,10 @@ class nsHtml5Speculation : public nsAHtml5TreeOpSink
PRInt32 GetStart() {
return mStart;
}
PRInt32 GetStartLineNumber() {
return mStartLineNumber;
}
nsAHtml5TreeBuilderState* GetSnapshot() {
return mSnapshot;
@ -89,6 +94,11 @@ class nsHtml5Speculation : public nsAHtml5TreeOpSink
* The start index of this speculation in the first buffer
*/
PRInt32 mStart;
/**
* The current line number at the start of the speculation
*/
PRInt32 mStartLineNumber;
nsAutoPtr<nsAHtml5TreeBuilderState> mSnapshot;

Просмотреть файл

@ -757,8 +757,10 @@ nsHtml5StreamParser::ParseAvailableData()
nsHtml5Speculation* speculation =
new nsHtml5Speculation(mFirstBuffer,
mFirstBuffer->getStart(),
mTokenizer->getLineNumber(),
mTreeBuilder->newSnapshot());
mTreeBuilder->AddSnapshotToScript(speculation->GetSnapshot());
mTreeBuilder->AddSnapshotToScript(speculation->GetSnapshot(),
speculation->GetStartLineNumber());
mTreeBuilder->Flush();
if (NS_FAILED(NS_DispatchToMainThread(mExecutorFlusher))) {
NS_WARNING("failed to dispatch executor flush event");
@ -855,6 +857,7 @@ nsHtml5StreamParser::ContinueAfterScripts(nsHtml5Tokenizer* aTokenizer,
nsHtml5Speculation* speculation = mSpeculations.ElementAt(0);
mFirstBuffer = speculation->GetBuffer();
mFirstBuffer->setStart(speculation->GetStart());
mTokenizer->setLineNumber(speculation->GetStartLineNumber());
nsHtml5UTF16Buffer* buffer = mFirstBuffer->next;
while (buffer) {
buffer->setStart(0);

Просмотреть файл

@ -140,8 +140,13 @@ nsIContent**
nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5HtmlAttributes* aAttributes)
{
NS_PRECONDITION(aAttributes, "Got null attributes.");
nsIContent** content = AllocateContentHandle();
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(aNamespace, aName, aAttributes, content);
// Start wall of code for speculative loading
// Start wall of code for speculative loading and line numbers
if (mSpeculativeLoader) {
switch (aNamespace) {
@ -152,6 +157,10 @@ nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5Htm
Dispatch(new nsHtml5SpeculativeImage(mSpeculativeLoader, *url));
}
} else if (nsHtml5Atoms::script == aName) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpSetScriptLineNumber, content, tokenizer->getLineNumber());
nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
if (url) {
nsString* charset = aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
@ -179,6 +188,10 @@ nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5Htm
if (url) {
Dispatch(new nsHtml5SpeculativeImage(mSpeculativeLoader, *url));
}
} else if (nsHtml5Atoms::style == aName) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
}
break;
case kNameSpaceID_SVG:
@ -188,6 +201,10 @@ nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5Htm
Dispatch(new nsHtml5SpeculativeImage(mSpeculativeLoader, *url));
}
} else if (nsHtml5Atoms::script == aName) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpSetScriptLineNumber, content, tokenizer->getLineNumber());
nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
if (url) {
nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
@ -197,6 +214,10 @@ nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5Htm
(type) ? *type : EmptyString()));
}
} else if (nsHtml5Atoms::style == aName) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
if (url) {
Dispatch(new nsHtml5SpeculativeStyle(mSpeculativeLoader,
@ -206,14 +227,21 @@ nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5Htm
}
break;
}
} else if (aNamespace != kNameSpaceID_MathML) {
// No speculative loader--just line numbers
if (nsHtml5Atoms::style == aName) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
} else if (nsHtml5Atoms::script == aName) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpSetScriptLineNumber, content, tokenizer->getLineNumber());
}
}
// End wall of code for speculative loading
nsIContent** content = AllocateContentHandle();
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(aNamespace, aName, aAttributes, content);
return content;
}
@ -584,11 +612,11 @@ nsHtml5TreeBuilder::NeedsCharsetSwitchTo(const nsACString& aCharset)
}
void
nsHtml5TreeBuilder::AddSnapshotToScript(nsAHtml5TreeBuilderState* aSnapshot)
nsHtml5TreeBuilder::AddSnapshotToScript(nsAHtml5TreeBuilderState* aSnapshot, PRInt32 aLine)
{
NS_PRECONDITION(HasScript(), "No script to add a snapshot to!");
NS_PRECONDITION(aSnapshot, "Got null snapshot.");
mOpQueue.ElementAt(mOpQueue.Length() - 1).SetSnapshot(aSnapshot);
mOpQueue.ElementAt(mOpQueue.Length() - 1).SetSnapshot(aSnapshot, aLine);
}
void

Просмотреть файл

@ -83,7 +83,7 @@
void NeedsCharsetSwitchTo(const nsACString& aEncoding);
void AddSnapshotToScript(nsAHtml5TreeBuilderState* aSnapshot);
void AddSnapshotToScript(nsAHtml5TreeBuilderState* aSnapshot, PRInt32 aLine);
inline void Dispatch(nsIRunnable* aEvent) {
if (NS_FAILED(NS_DispatchToMainThread(aEvent))) {

Просмотреть файл

@ -585,9 +585,9 @@ nsHtml5TreeOpExecutor::ForcedFlush(nsTArray<nsHtml5TreeOperation>& aOpQueue)
}
void
nsHtml5TreeOpExecutor::InitializeDocWriteParserState(nsAHtml5TreeBuilderState* aState)
nsHtml5TreeOpExecutor::InitializeDocWriteParserState(nsAHtml5TreeBuilderState* aState, PRInt32 aLine)
{
static_cast<nsHtml5Parser*> (mParser.get())->InitializeDocWriteParserState(aState);
static_cast<nsHtml5Parser*> (mParser.get())->InitializeDocWriteParserState(aState, aLine);
}
void

Просмотреть файл

@ -224,7 +224,7 @@ class nsHtml5TreeOpExecutor : public nsContentSink,
mScriptElement = aScript;
}
void InitializeDocWriteParserState(nsAHtml5TreeBuilderState* aState);
void InitializeDocWriteParserState(nsAHtml5TreeBuilderState* aState, PRInt32 aLine);
PRBool IsScriptEnabled();

Просмотреть файл

@ -324,7 +324,7 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder)
nsIContent* node = *(mOne.node);
nsAHtml5TreeBuilderState* snapshot = mTwo.state;
if (snapshot) {
aBuilder->InitializeDocWriteParserState(snapshot);
aBuilder->InitializeDocWriteParserState(snapshot, mInt);
}
aBuilder->SetScriptElement(node);
return rv;
@ -392,6 +392,20 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder)
aBuilder->DocumentMode(mOne.mode);
return rv;
}
case eTreeOpSetStyleLineNumber: {
nsIContent* node = *(mOne.node);
nsCOMPtr<nsIStyleSheetLinkingElement> ssle = do_QueryInterface(node);
NS_ASSERTION(ssle, "Node didn't QI to style.");
ssle->SetLineNumber(mInt);
return rv;
}
case eTreeOpSetScriptLineNumber: {
nsIContent* node = *(mOne.node);
nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(node);
NS_ASSERTION(sele, "Node didn't QI to script.");
sele->SetScriptLineNumber(mInt);
return rv;
}
default: {
NS_NOTREACHED("Bogus tree op");
}

Просмотреть файл

@ -74,6 +74,8 @@ enum eHtml5TreeOperation {
eTreeOpProcessOfflineManifest,
eTreeOpMarkMalformedIfScript,
eTreeOpStreamEnded,
eTreeOpSetStyleLineNumber,
eTreeOpSetScriptLineNumber,
eTreeOpStartLayout
};
@ -221,14 +223,26 @@ class nsHtml5TreeOperation {
mOne.charPtr = str;
}
inline void Init(eHtml5TreeOperation aOpCode,
nsIContent** aNode,
PRInt32 aInt) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
mOpCode = aOpCode;
mOne.node = aNode;
mInt = aInt;
}
inline PRBool IsRunScript() {
return mOpCode == eTreeOpRunScript;
}
inline void SetSnapshot(nsAHtml5TreeBuilderState* aSnapshot) {
inline void SetSnapshot(nsAHtml5TreeBuilderState* aSnapshot, PRInt32 aLine) {
NS_ASSERTION(IsRunScript(),
"Setting a snapshot for a tree operation other than eTreeOpRunScript!");
mTwo.state = aSnapshot;
mInt = aLine;
}
nsresult Perform(nsHtml5TreeOpExecutor* aBuilder);