зеркало из https://github.com/mozilla/pjs.git
Bug 483015 - Expose HTML line number to JS and CSS parsers in the HTML5 parser. r=bnewman, a=beltzner.
This commit is contained in:
Родитель
75191b2cf1
Коммит
2b0cb4fef4
|
@ -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;
|
||||
|
@ -379,6 +379,11 @@ class nsHtml5Parser : public nsIParser,
|
|||
*/
|
||||
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();
|
||||
|
@ -62,6 +63,10 @@ class nsHtml5Speculation : public nsAHtml5TreeOpSink
|
|||
return mStart;
|
||||
}
|
||||
|
||||
PRInt32 GetStartLineNumber() {
|
||||
return mStartLineNumber;
|
||||
}
|
||||
|
||||
nsAHtml5TreeBuilderState* GetSnapshot() {
|
||||
return mSnapshot;
|
||||
}
|
||||
|
@ -90,6 +95,11 @@ class nsHtml5Speculation : public nsAHtml5TreeOpSink
|
|||
*/
|
||||
PRInt32 mStart;
|
||||
|
||||
/**
|
||||
* The current line number at the start of the speculation
|
||||
*/
|
||||
PRInt32 mStartLineNumber;
|
||||
|
||||
nsAutoPtr<nsAHtml5TreeBuilderState> mSnapshot;
|
||||
|
||||
nsTArray<nsHtml5TreeOperation> mOpQueue;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -141,7 +141,12 @@ nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5Htm
|
|||
{
|
||||
NS_PRECONDITION(aAttributes, "Got null attributes.");
|
||||
|
||||
// Start wall of code for speculative loading
|
||||
nsIContent** content = AllocateContentHandle();
|
||||
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
|
||||
// XXX if null, OOM!
|
||||
treeOp->Init(aNamespace, aName, aAttributes, content);
|
||||
|
||||
// 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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче