diff -r 000000000000 -r 6474c204b198 parser/html/nsHtml5TreeBuilderCppSupplement.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,1461 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 sw=2 et tw=78: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsError.h" +#include "nsIPresShell.h" +#include "nsNodeUtils.h" +#include "nsIFrame.h" +#include "mozilla/Likely.h" + +class nsPresContext; + +nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsHtml5OplessBuilder* aBuilder) + : scriptingEnabled(false) + , fragment(false) + , contextNode(nullptr) + , formPointer(nullptr) + , headPointer(nullptr) + , mBuilder(aBuilder) + , mViewSource(nullptr) + , mOpSink(nullptr) + , mHandles(nullptr) + , mHandlesUsed(0) + , mSpeculativeLoadStage(nullptr) + , mCurrentHtmlScriptIsAsyncOrDefer(false) + , mPreventScriptExecution(false) +#ifdef DEBUG + , mActive(false) +#endif +{ + MOZ_COUNT_CTOR(nsHtml5TreeBuilder); +} + +nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink, + nsHtml5TreeOpStage* aStage) + : scriptingEnabled(false) + , fragment(false) + , contextNode(nullptr) + , formPointer(nullptr) + , headPointer(nullptr) + , mBuilder(nullptr) + , mViewSource(nullptr) + , mOpSink(aOpSink) + , mHandles(new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH]) + , mHandlesUsed(0) + , mSpeculativeLoadStage(aStage) + , mCurrentHtmlScriptIsAsyncOrDefer(false) + , mPreventScriptExecution(false) +#ifdef DEBUG + , mActive(false) +#endif +{ + MOZ_COUNT_CTOR(nsHtml5TreeBuilder); +} + +nsHtml5TreeBuilder::~nsHtml5TreeBuilder() +{ + MOZ_COUNT_DTOR(nsHtml5TreeBuilder); + NS_ASSERTION(!mActive, "nsHtml5TreeBuilder deleted without ever calling end() on it!"); + mOpQueue.Clear(); +} + +nsIContentHandle* +nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName, nsHtml5HtmlAttributes* aAttributes) +{ + NS_PRECONDITION(aAttributes, "Got null attributes."); + NS_PRECONDITION(aName, "Got null name."); + NS_PRECONDITION(aNamespace == kNameSpaceID_XHTML || + aNamespace == kNameSpaceID_SVG || + aNamespace == kNameSpaceID_MathML, + "Bogus namespace."); + + if (mBuilder) { + nsCOMPtr name = nsHtml5TreeOperation::Reget(aName); + nsIContent* elem = + nsHtml5TreeOperation::CreateElement(aNamespace, + name, + aAttributes, + mozilla::dom::FROM_PARSER_FRAGMENT, + mBuilder); + if (MOZ_UNLIKELY(aAttributes != tokenizer->GetAttributes() && + aAttributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES)) { + delete aAttributes; + } + return elem; + } + + nsIContentHandle* content = AllocateContentHandle(); + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(aNamespace, + aName, + aAttributes, + content, + !!mSpeculativeLoadStage); + // mSpeculativeLoadStage is non-null only in the off-the-main-thread + // tree builder, which handles the network stream + + // Start wall of code for speculative loading and line numbers + + if (mSpeculativeLoadStage) { + switch (aNamespace) { + case kNameSpaceID_XHTML: + if (nsHtml5Atoms::img == aName) { + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC); + if (url) { + nsString* crossOrigin = + aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); + mSpeculativeLoadQueue.AppendElement()-> + InitImage(*url, + crossOrigin ? *crossOrigin : NullString()); + } + } else if (nsHtml5Atoms::script == aName) { + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber()); + + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC); + if (url) { + nsString* charset = aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET); + nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); + nsString* crossOrigin = + aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); + mSpeculativeLoadQueue.AppendElement()-> + InitScript(*url, + (charset) ? *charset : EmptyString(), + (type) ? *type : EmptyString(), + (crossOrigin) ? *crossOrigin : NullString(), + mode == NS_HTML5TREE_BUILDER_IN_HEAD); + mCurrentHtmlScriptIsAsyncOrDefer = + aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) || + aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER); + } + } else if (nsHtml5Atoms::link == aName) { + nsString* rel = aAttributes->getValue(nsHtml5AttributeName::ATTR_REL); + // Not splitting on space here is bogus but the old parser didn't even + // do a case-insensitive check. + if (rel && rel->LowerCaseEqualsASCII("stylesheet")) { + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); + if (url) { + nsString* charset = aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET); + nsString* crossOrigin = + aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); + mSpeculativeLoadQueue.AppendElement()-> + InitStyle(*url, + (charset) ? *charset : EmptyString(), + (crossOrigin) ? *crossOrigin : NullString()); + } + } + } else if (nsHtml5Atoms::video == aName) { + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER); + if (url) { + mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString()); + } + } else if (nsHtml5Atoms::style == aName) { + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber()); + } else if (nsHtml5Atoms::html == aName) { + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST); + if (url) { + mSpeculativeLoadQueue.AppendElement()->InitManifest(*url); + } else { + mSpeculativeLoadQueue.AppendElement()->InitManifest(EmptyString()); + } + } else if (nsHtml5Atoms::base == aName) { + nsString* url = + aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); + if (url) { + mSpeculativeLoadQueue.AppendElement()->InitBase(*url); + } + } + break; + case kNameSpaceID_SVG: + if (nsHtml5Atoms::image == aName) { + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); + if (url) { + mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString()); + } + } else if (nsHtml5Atoms::script == aName) { + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber()); + + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); + if (url) { + nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); + nsString* crossOrigin = + aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); + mSpeculativeLoadQueue.AppendElement()-> + InitScript(*url, + EmptyString(), + (type) ? *type : EmptyString(), + (crossOrigin) ? *crossOrigin : NullString(), + mode == NS_HTML5TREE_BUILDER_IN_HEAD); + } + } else if (nsHtml5Atoms::style == aName) { + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber()); + + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); + if (url) { + nsString* crossOrigin = + aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); + mSpeculativeLoadQueue.AppendElement()-> + InitStyle(*url, EmptyString(), + (crossOrigin) ? *crossOrigin : NullString()); + } + } + break; + } + } else if (aNamespace != kNameSpaceID_MathML) { + // No speculative loader--just line numbers and defer/async check + if (nsHtml5Atoms::style == aName) { + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber()); + } else if (nsHtml5Atoms::script == aName) { + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber()); + if (aNamespace == kNameSpaceID_XHTML) { + mCurrentHtmlScriptIsAsyncOrDefer = + aAttributes->contains(nsHtml5AttributeName::ATTR_SRC) && + (aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) || + aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER)); + } + } else if (aNamespace == kNameSpaceID_XHTML && nsHtml5Atoms::html == aName) { + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST); + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + if (url) { + treeOp->Init(eTreeOpProcessOfflineManifest, *url); + } else { + treeOp->Init(eTreeOpProcessOfflineManifest, EmptyString()); + } + } + } + + // End wall of code for speculative loading + + return content; +} + +nsIContentHandle* +nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName, nsHtml5HtmlAttributes* aAttributes, nsIContentHandle* aFormElement) +{ + nsIContentHandle* content = createElement(aNamespace, aName, aAttributes); + if (aFormElement) { + if (mBuilder) { + nsHtml5TreeOperation::SetFormElement(static_cast(content), + static_cast(aFormElement)); + } else { + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpSetFormElement, content, aFormElement); + } + } + return content; +} + +nsIContentHandle* +nsHtml5TreeBuilder::createHtmlElementSetAsRoot(nsHtml5HtmlAttributes* aAttributes) +{ + nsIContentHandle* content = createElement(kNameSpaceID_XHTML, nsHtml5Atoms::html, aAttributes); + if (mBuilder) { + nsresult rv = nsHtml5TreeOperation::AppendToDocument(static_cast(content), + mBuilder); + if (NS_FAILED(rv)) { + MarkAsBrokenAndRequestSuspension(rv); + } + } else { + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpAppendToDocument, content); + } + return content; +} + +void +nsHtml5TreeBuilder::detachFromParent(nsIContentHandle* aElement) +{ + NS_PRECONDITION(aElement, "Null element"); + + if (mBuilder) { + nsHtml5TreeOperation::Detach(static_cast(aElement), + mBuilder); + return; + } + + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpDetach, aElement); +} + +void +nsHtml5TreeBuilder::appendElement(nsIContentHandle* aChild, nsIContentHandle* aParent) +{ + NS_PRECONDITION(aChild, "Null child"); + NS_PRECONDITION(aParent, "Null parent"); + if (deepTreeSurrogateParent) { + return; + } + + if (mBuilder) { + nsresult rv = nsHtml5TreeOperation::Append(static_cast(aChild), + static_cast(aParent), + mBuilder); + if (NS_FAILED(rv)) { + MarkAsBrokenAndRequestSuspension(rv); + } + return; + } + + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpAppend, aChild, aParent); +} + +void +nsHtml5TreeBuilder::appendChildrenToNewParent(nsIContentHandle* aOldParent, nsIContentHandle* aNewParent) +{ + NS_PRECONDITION(aOldParent, "Null old parent"); + NS_PRECONDITION(aNewParent, "Null new parent"); + + if (mBuilder) { + nsresult rv = nsHtml5TreeOperation::AppendChildrenToNewParent( + static_cast(aOldParent), + static_cast(aNewParent), + mBuilder); + if (NS_FAILED(rv)) { + MarkAsBrokenAndRequestSuspension(rv); + } + return; + } + + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpAppendChildrenToNewParent, aOldParent, aNewParent); +} + +void +nsHtml5TreeBuilder::insertFosterParentedCharacters(char16_t* aBuffer, int32_t aStart, int32_t aLength, nsIContentHandle* aTable, nsIContentHandle* aStackParent) +{ + NS_PRECONDITION(aBuffer, "Null buffer"); + NS_PRECONDITION(aTable, "Null table"); + NS_PRECONDITION(aStackParent, "Null stack parent"); + MOZ_ASSERT(!aStart, "aStart must always be zero."); + + if (mBuilder) { + nsresult rv = nsHtml5TreeOperation::FosterParentText( + static_cast(aStackParent), + aBuffer, // XXX aStart always ignored??? + aLength, + static_cast(aTable), + mBuilder); + if (NS_FAILED(rv)) { + MarkAsBrokenAndRequestSuspension(rv); + } + return; + } + + char16_t* bufferCopy = new char16_t[aLength]; + memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t)); + + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpFosterParentText, bufferCopy, aLength, aStackParent, aTable); +} + +void +nsHtml5TreeBuilder::insertFosterParentedChild(nsIContentHandle* aChild, nsIContentHandle* aTable, nsIContentHandle* aStackParent) +{ + NS_PRECONDITION(aChild, "Null child"); + NS_PRECONDITION(aTable, "Null table"); + NS_PRECONDITION(aStackParent, "Null stack parent"); + + if (mBuilder) { + nsresult rv = nsHtml5TreeOperation::FosterParent( + static_cast(aChild), + static_cast(aStackParent), + static_cast(aTable), + mBuilder); + if (NS_FAILED(rv)) { + MarkAsBrokenAndRequestSuspension(rv); + } + return; + } + + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpFosterParent, aChild, aStackParent, aTable); +} + +void +nsHtml5TreeBuilder::appendCharacters(nsIContentHandle* aParent, char16_t* aBuffer, int32_t aStart, int32_t aLength) +{ + NS_PRECONDITION(aBuffer, "Null buffer"); + NS_PRECONDITION(aParent, "Null parent"); + MOZ_ASSERT(!aStart, "aStart must always be zero."); + + if (mBuilder) { + nsresult rv = nsHtml5TreeOperation::AppendText( + aBuffer, // XXX aStart always ignored??? + aLength, + static_cast(deepTreeSurrogateParent ? + deepTreeSurrogateParent : aParent), + mBuilder); + if (NS_FAILED(rv)) { + MarkAsBrokenAndRequestSuspension(rv); + } + return; + } + + char16_t* bufferCopy = new char16_t[aLength]; + memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t)); + + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpAppendText, bufferCopy, aLength, + deepTreeSurrogateParent ? deepTreeSurrogateParent : aParent); +} + +void +nsHtml5TreeBuilder::appendIsindexPrompt(nsIContentHandle* aParent) +{ + NS_PRECONDITION(aParent, "Null parent"); + + if (mBuilder) { + nsresult rv = nsHtml5TreeOperation::AppendIsindexPrompt( + static_cast(aParent), + mBuilder); + if (NS_FAILED(rv)) { + MarkAsBrokenAndRequestSuspension(rv); + } + return; + } + + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpAppendIsindexPrompt, aParent); +} + +void +nsHtml5TreeBuilder::appendComment(nsIContentHandle* aParent, char16_t* aBuffer, int32_t aStart, int32_t aLength) +{ + NS_PRECONDITION(aBuffer, "Null buffer"); + NS_PRECONDITION(aParent, "Null parent"); + MOZ_ASSERT(!aStart, "aStart must always be zero."); + + if (deepTreeSurrogateParent) { + return; + } + + if (mBuilder) { + nsresult rv = nsHtml5TreeOperation::AppendComment( + static_cast(aParent), + aBuffer, // XXX aStart always ignored??? + aLength, + mBuilder); + if (NS_FAILED(rv)) { + MarkAsBrokenAndRequestSuspension(rv); + } + return; + } + + char16_t* bufferCopy = new char16_t[aLength]; + memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t)); + + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpAppendComment, bufferCopy, aLength, aParent); +} + +void +nsHtml5TreeBuilder::appendCommentToDocument(char16_t* aBuffer, int32_t aStart, int32_t aLength) +{ + NS_PRECONDITION(aBuffer, "Null buffer"); + MOZ_ASSERT(!aStart, "aStart must always be zero."); + + if (mBuilder) { + nsresult rv = nsHtml5TreeOperation::AppendCommentToDocument( + aBuffer, // XXX aStart always ignored??? + aLength, + mBuilder); + if (NS_FAILED(rv)) { + MarkAsBrokenAndRequestSuspension(rv); + } + return; + } + + char16_t* bufferCopy = new char16_t[aLength]; + memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t)); + + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpAppendCommentToDocument, bufferCopy, aLength); +} + +void +nsHtml5TreeBuilder::addAttributesToElement(nsIContentHandle* aElement, nsHtml5HtmlAttributes* aAttributes) +{ + NS_PRECONDITION(aElement, "Null element"); + NS_PRECONDITION(aAttributes, "Null attributes"); + + if (aAttributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) { + return; + } + + if (mBuilder) { + MOZ_ASSERT(aAttributes == tokenizer->GetAttributes(), + "Using attribute other than the tokenizer's to add to body or html."); + nsresult rv = nsHtml5TreeOperation::AddAttributes( + static_cast(aElement), + aAttributes, + mBuilder); + if (NS_FAILED(rv)) { + MarkAsBrokenAndRequestSuspension(rv); + } + return; + } + + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(aElement, aAttributes); +} + +void +nsHtml5TreeBuilder::markMalformedIfScript(nsIContentHandle* aElement) +{ + NS_PRECONDITION(aElement, "Null element"); + + if (mBuilder) { + nsHtml5TreeOperation::MarkMalformedIfScript( + static_cast(aElement)); + return; + } + + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpMarkMalformedIfScript, aElement); +} + +void +nsHtml5TreeBuilder::start(bool fragment) +{ + mCurrentHtmlScriptIsAsyncOrDefer = false; + deepTreeSurrogateParent = nullptr; +#ifdef DEBUG + mActive = true; +#endif +} + +void +nsHtml5TreeBuilder::end() +{ + mOpQueue.Clear(); +#ifdef DEBUG + mActive = false; +#endif +} + +void +nsHtml5TreeBuilder::appendDoctypeToDocument(nsIAtom* aName, nsString* aPublicId, nsString* aSystemId) +{ + NS_PRECONDITION(aName, "Null name"); + + if (mBuilder) { + nsCOMPtr name = nsHtml5TreeOperation::Reget(aName); + nsresult rv = + nsHtml5TreeOperation::AppendDoctypeToDocument(name, + *aPublicId, + *aSystemId, + mBuilder); + if (NS_FAILED(rv)) { + MarkAsBrokenAndRequestSuspension(rv); + } + return; + } + + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(aName, *aPublicId, *aSystemId); + // nsXMLContentSink can flush here, but what's the point? + // It can also interrupt here, but we can't. +} + +void +nsHtml5TreeBuilder::elementPushed(int32_t aNamespace, nsIAtom* aName, nsIContentHandle* aElement) +{ + NS_ASSERTION(aNamespace == kNameSpaceID_XHTML || aNamespace == kNameSpaceID_SVG || aNamespace == kNameSpaceID_MathML, "Element isn't HTML, SVG or MathML!"); + NS_ASSERTION(aName, "Element doesn't have local name!"); + NS_ASSERTION(aElement, "No element!"); + /* + * The frame constructor uses recursive algorithms, so it can't deal with + * arbitrarily deep trees. This is especially a problem on Windows where + * the permitted depth of the runtime stack is rather small. + * + * The following is a protection against author incompetence--not against + * malice. There are other ways to make the DOM deep anyway. + * + * The basic idea is that when the tree builder stack gets too deep, + * append operations no longer append to the node that the HTML parsing + * algorithm says they should but instead text nodes are append to the last + * element that was seen before a magic tree builder stack threshold was + * reached and element and comment nodes aren't appended to the DOM at all. + * + * However, for security reasons, non-child descendant text nodes inside an + * SVG script or style element should not become children. Also, non-cell + * table elements shouldn't be used as surrogate parents for user experience + * reasons. + */ + if (!deepTreeSurrogateParent && currentPtr >= MAX_REFLOW_DEPTH && + !(aName == nsHtml5Atoms::script || + aName == nsHtml5Atoms::table || + aName == nsHtml5Atoms::thead || + aName == nsHtml5Atoms::tfoot || + aName == nsHtml5Atoms::tbody || + aName == nsHtml5Atoms::tr || + aName == nsHtml5Atoms::colgroup || + aName == nsHtml5Atoms::style)) { + deepTreeSurrogateParent = aElement; + } + if (aNamespace != kNameSpaceID_XHTML) { + return; + } + if (aName == nsHtml5Atoms::body || aName == nsHtml5Atoms::frameset) { + if (mBuilder) { + // InnerHTML and DOMParser shouldn't start layout anyway + return; + } + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpStartLayout); + return; + } + if (aName == nsHtml5Atoms::input || + aName == nsHtml5Atoms::button) { + if (!formPointer) { + // If form inputs don't belong to a form, their state preservation + // won't work right without an append notification flush at this + // point. See bug 497861. + if (mBuilder) { + mBuilder->FlushPendingAppendNotifications(); + } else { + mOpQueue.AppendElement()->Init(eTreeOpFlushPendingAppendNotifications); + } + } + if (mBuilder) { + nsHtml5TreeOperation::DoneCreatingElement(static_cast(aElement)); + } else { + mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement); + } + return; + } + if (aName == nsHtml5Atoms::audio || + aName == nsHtml5Atoms::video || + aName == nsHtml5Atoms::menuitem) { + if (mBuilder) { + nsHtml5TreeOperation::DoneCreatingElement(static_cast(aElement)); + } else { + mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement); + } + return; + } +} + +void +nsHtml5TreeBuilder::elementPopped(int32_t aNamespace, nsIAtom* aName, nsIContentHandle* aElement) +{ + NS_ASSERTION(aNamespace == kNameSpaceID_XHTML || aNamespace == kNameSpaceID_SVG || aNamespace == kNameSpaceID_MathML, "Element isn't HTML, SVG or MathML!"); + NS_ASSERTION(aName, "Element doesn't have local name!"); + NS_ASSERTION(aElement, "No element!"); + if (deepTreeSurrogateParent && currentPtr <= MAX_REFLOW_DEPTH) { + deepTreeSurrogateParent = nullptr; + } + if (aNamespace == kNameSpaceID_MathML) { + return; + } + // we now have only SVG and HTML + if (aName == nsHtml5Atoms::script) { + if (mPreventScriptExecution) { + if (mBuilder) { + nsHtml5TreeOperation::PreventScriptExecution(static_cast(aElement)); + return; + } + mOpQueue.AppendElement()->Init(eTreeOpPreventScriptExecution, aElement); + return; + } + if (mBuilder) { + return; + } + if (mCurrentHtmlScriptIsAsyncOrDefer) { + NS_ASSERTION(aNamespace == kNameSpaceID_XHTML, + "Only HTML scripts may be async/defer."); + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpRunScriptAsyncDefer, aElement); + mCurrentHtmlScriptIsAsyncOrDefer = false; + return; + } + requestSuspension(); + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->InitScript(aElement); + return; + } + if (aName == nsHtml5Atoms::title) { + if (mBuilder) { + nsHtml5TreeOperation::DoneAddingChildren(static_cast(aElement), mBuilder); + return; + } + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpDoneAddingChildren, aElement); + return; + } + if (aName == nsHtml5Atoms::style || (aNamespace == kNameSpaceID_XHTML && aName == nsHtml5Atoms::link)) { + if (mBuilder) { + MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(), + "Scripts must be blocked."); + mBuilder->FlushPendingAppendNotifications(); + mBuilder->UpdateStyleSheet(static_cast(aElement)); + return; + } + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpUpdateStyleSheet, aElement); + return; + } + if (aNamespace == kNameSpaceID_SVG) { + if (aName == nsHtml5Atoms::svg) { + if (mBuilder) { + nsHtml5TreeOperation::SvgLoad(static_cast(aElement)); + return; + } + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpSvgLoad, aElement); + } + return; + } + // we now have only HTML + // Some HTML nodes need DoneAddingChildren() called to initialize + // properly (e.g. form state restoration). + // XXX expose ElementName group here and do switch + if (aName == nsHtml5Atoms::object || + aName == nsHtml5Atoms::applet) { + if (mBuilder) { + nsHtml5TreeOperation::DoneAddingChildren(static_cast(aElement), mBuilder); + return; + } + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpDoneAddingChildren, aElement); + return; + } + if (aName == nsHtml5Atoms::select || + aName == nsHtml5Atoms::textarea) { + if (!formPointer) { + // If form inputs don't belong to a form, their state preservation + // won't work right without an append notification flush at this + // point. See bug 497861 and bug 539895. + if (mBuilder) { + mBuilder->FlushPendingAppendNotifications(); + } else { + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpFlushPendingAppendNotifications); + } + } + if (mBuilder) { + nsHtml5TreeOperation::DoneAddingChildren(static_cast(aElement), mBuilder); + return; + } + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpDoneAddingChildren, aElement); + return; + } + if (aName == nsHtml5Atoms::meta && !fragment && !mBuilder) { + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpProcessMeta, aElement); + return; + } + return; +} + +void +nsHtml5TreeBuilder::accumulateCharacters(const char16_t* aBuf, int32_t aStart, int32_t aLength) +{ + int32_t newFillLen = charBufferLen + aLength; + if (newFillLen > charBuffer.length) { + int32_t newAllocLength = newFillLen + (newFillLen >> 1); + jArray newBuf = jArray::newJArray(newAllocLength); + memcpy(newBuf, charBuffer, sizeof(char16_t) * charBufferLen); + charBuffer = newBuf; + } + memcpy(charBuffer + charBufferLen, aBuf + aStart, sizeof(char16_t) * aLength); + charBufferLen = newFillLen; +} + +nsIContentHandle* +nsHtml5TreeBuilder::AllocateContentHandle() +{ + if (MOZ_UNLIKELY(mBuilder)) { + MOZ_ASSUME_UNREACHABLE("Must never allocate a handle with builder."); + return nullptr; + } + if (mHandlesUsed == NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH) { + mOldHandles.AppendElement(mHandles.forget()); + mHandles = new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH]; + mHandlesUsed = 0; + } +#ifdef DEBUG + mHandles[mHandlesUsed] = (nsIContent*)0xC0DEDBAD; +#endif + return &mHandles[mHandlesUsed++]; +} + +bool +nsHtml5TreeBuilder::HasScript() +{ + uint32_t len = mOpQueue.Length(); + if (!len) { + return false; + } + return mOpQueue.ElementAt(len - 1).IsRunScript(); +} + +bool +nsHtml5TreeBuilder::Flush(bool aDiscretionary) +{ + if (MOZ_UNLIKELY(mBuilder)) { + MOZ_ASSUME_UNREACHABLE("Must never flush with builder."); + return false; + } + if (!aDiscretionary || + !(charBufferLen && + currentPtr >= 0 && + stack[currentPtr]->isFosterParenting())) { + // Don't flush text on discretionary flushes if the current element on + // the stack is a foster-parenting element and there's pending text, + // because flushing in that case would make the tree shape dependent on + // where the flush points fall. + flushCharacters(); + } + FlushLoads(); + if (mOpSink) { + bool hasOps = !mOpQueue.IsEmpty(); + if (hasOps) { + mOpSink->MoveOpsFrom(mOpQueue); + } + return hasOps; + } + // no op sink: throw away ops + mOpQueue.Clear(); + return false; +} + +void +nsHtml5TreeBuilder::FlushLoads() +{ + if (MOZ_UNLIKELY(mBuilder)) { + MOZ_ASSUME_UNREACHABLE("Must never flush loads with builder."); + return; + } + if (!mSpeculativeLoadQueue.IsEmpty()) { + mSpeculativeLoadStage->MoveSpeculativeLoadsFrom(mSpeculativeLoadQueue); + } +} + +void +nsHtml5TreeBuilder::SetDocumentCharset(nsACString& aCharset, + int32_t aCharsetSource) +{ + if (mBuilder) { + mBuilder->SetDocumentCharsetAndSource(aCharset, aCharsetSource); + } else if (mSpeculativeLoadStage) { + mSpeculativeLoadQueue.AppendElement()->InitSetDocumentCharset( + aCharset, aCharsetSource); + } else { + mOpQueue.AppendElement()->Init( + eTreeOpSetDocumentCharset, aCharset, aCharsetSource); + } +} + +void +nsHtml5TreeBuilder::StreamEnded() +{ + MOZ_ASSERT(!mBuilder, "Must not call StreamEnded with builder."); + MOZ_ASSERT(!fragment, "Must not parse fragments off the main thread."); + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpStreamEnded); +} + +void +nsHtml5TreeBuilder::NeedsCharsetSwitchTo(const nsACString& aCharset, + int32_t aCharsetSource, + int32_t aLineNumber) +{ + if (MOZ_UNLIKELY(mBuilder)) { + MOZ_ASSUME_UNREACHABLE("Must never switch charset with builder."); + return; + } + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(eTreeOpNeedsCharsetSwitchTo, + aCharset, + aCharsetSource, + aLineNumber); +} + +void +nsHtml5TreeBuilder::MaybeComplainAboutCharset(const char* aMsgId, + bool aError, + int32_t aLineNumber) +{ + if (MOZ_UNLIKELY(mBuilder)) { + MOZ_ASSUME_UNREACHABLE("Must never complain about charset with builder."); + return; + } + mOpQueue.AppendElement()->Init(aMsgId, aError, aLineNumber); +} + +void +nsHtml5TreeBuilder::AddSnapshotToScript(nsAHtml5TreeBuilderState* aSnapshot, int32_t aLine) +{ + if (MOZ_UNLIKELY(mBuilder)) { + MOZ_ASSUME_UNREACHABLE("Must never use snapshots with builder."); + return; + } + NS_PRECONDITION(HasScript(), "No script to add a snapshot to!"); + NS_PRECONDITION(aSnapshot, "Got null snapshot."); + mOpQueue.ElementAt(mOpQueue.Length() - 1).SetSnapshot(aSnapshot, aLine); +} + +void +nsHtml5TreeBuilder::DropHandles() +{ + MOZ_ASSERT(!mBuilder, "Must not drop handles with builder."); + mOldHandles.Clear(); + mHandlesUsed = 0; +} + +void +nsHtml5TreeBuilder::MarkAsBroken(nsresult aRv) +{ + if (MOZ_UNLIKELY(mBuilder)) { + MOZ_ASSUME_UNREACHABLE("Must not call this with builder."); + return; + } + mOpQueue.Clear(); // Previous ops don't matter anymore + mOpQueue.AppendElement()->Init(aRv); +} + +void +nsHtml5TreeBuilder::StartPlainTextViewSource(const nsAutoString& aTitle) +{ + MOZ_ASSERT(!mBuilder, "Must not view source with builder."); + startTag(nsHtml5ElementName::ELT_TITLE, + nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES, + false); + + // XUL will add the "Source of: " prefix. + uint32_t length = aTitle.Length(); + if (length > INT32_MAX) { + length = INT32_MAX; + } + characters(aTitle.get(), 0, (int32_t)length); + endTag(nsHtml5ElementName::ELT_TITLE); + + startTag(nsHtml5ElementName::ELT_LINK, + nsHtml5ViewSourceUtils::NewLinkAttributes(), + false); + + startTag(nsHtml5ElementName::ELT_BODY, + nsHtml5ViewSourceUtils::NewBodyAttributes(), + false); + + StartPlainTextBody(); +} + +void +nsHtml5TreeBuilder::StartPlainText() +{ + MOZ_ASSERT(!mBuilder, "Must not view source with builder."); + startTag(nsHtml5ElementName::ELT_LINK, + nsHtml5PlainTextUtils::NewLinkAttributes(), + false); + + StartPlainTextBody(); +} + +void +nsHtml5TreeBuilder::StartPlainTextBody() +{ + MOZ_ASSERT(!mBuilder, "Must not view source with builder."); + startTag(nsHtml5ElementName::ELT_PRE, + nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES, + false); + needToDropLF = false; +} + +// DocumentModeHandler +void +nsHtml5TreeBuilder::documentMode(nsHtml5DocumentMode m) +{ + if (mBuilder) { + mBuilder->SetDocumentMode(m); + return; + } + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + treeOp->Init(m); +} + +nsIContentHandle* +nsHtml5TreeBuilder::getDocumentFragmentForTemplate(nsIContentHandle* aTemplate) +{ + if (mBuilder) { + return nsHtml5TreeOperation::GetDocumentFragmentForTemplate(static_cast(aTemplate)); + } + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); + NS_ASSERTION(treeOp, "Tree op allocation failed."); + nsIContentHandle* fragHandle = AllocateContentHandle(); + treeOp->Init(eTreeOpGetDocumentFragmentForTemplate, aTemplate, fragHandle); + return fragHandle; +} + +nsIContentHandle* +nsHtml5TreeBuilder::getFormPointerForContext(nsIContentHandle* aContext) +{ + MOZ_ASSERT(mBuilder, "Must have builder."); + if (!aContext) { + return nullptr; + } + + MOZ_ASSERT(NS_IsMainThread()); + + // aContext must always be an element that already exists + // in the document. + nsIContent* contextNode = static_cast(aContext); + nsIContent* currentAncestor = contextNode; + + // We traverse the ancestors of the context node to find the nearest + // form pointer. This traversal is why aContext must not be an emtpy handle. + nsIContent* nearestForm = nullptr; + while (currentAncestor) { + if (currentAncestor->IsHTML(nsGkAtoms::form)) { + nearestForm = currentAncestor; + break; + } + currentAncestor = currentAncestor->GetParent(); + } + + if (!nearestForm) { + return nullptr; + } + + return nearestForm; +} + +// Error reporting + +void +nsHtml5TreeBuilder::EnableViewSource(nsHtml5Highlighter* aHighlighter) +{ + MOZ_ASSERT(!mBuilder, "Must not view source with builder."); + mViewSource = aHighlighter; +} + +void +nsHtml5TreeBuilder::errStrayStartTag(nsIAtom* aName) +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errStrayStartTag2", aName); + } +} + +void +nsHtml5TreeBuilder::errStrayEndTag(nsIAtom* aName) +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errStrayEndTag", aName); + } +} + +void +nsHtml5TreeBuilder::errUnclosedElements(int32_t aIndex, nsIAtom* aName) +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errUnclosedElements", aName); + } +} + +void +nsHtml5TreeBuilder::errUnclosedElementsImplied(int32_t aIndex, nsIAtom* aName) +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errUnclosedElementsImplied", + aName); + } +} + +void +nsHtml5TreeBuilder::errUnclosedElementsCell(int32_t aIndex) +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errUnclosedElementsCell"); + } +} + +void +nsHtml5TreeBuilder::errStrayDoctype() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errStrayDoctype"); + } +} + +void +nsHtml5TreeBuilder::errAlmostStandardsDoctype() +{ + if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) { + mViewSource->AddErrorToCurrentRun("errAlmostStandardsDoctype"); + } +} + +void +nsHtml5TreeBuilder::errQuirkyDoctype() +{ + if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) { + mViewSource->AddErrorToCurrentRun("errQuirkyDoctype"); + } +} + +void +nsHtml5TreeBuilder::errNonSpaceInTrailer() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errNonSpaceInTrailer"); + } +} + +void +nsHtml5TreeBuilder::errNonSpaceAfterFrameset() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errNonSpaceAfterFrameset"); + } +} + +void +nsHtml5TreeBuilder::errNonSpaceInFrameset() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errNonSpaceInFrameset"); + } +} + +void +nsHtml5TreeBuilder::errNonSpaceAfterBody() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errNonSpaceAfterBody"); + } +} + +void +nsHtml5TreeBuilder::errNonSpaceInColgroupInFragment() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errNonSpaceInColgroupInFragment"); + } +} + +void +nsHtml5TreeBuilder::errNonSpaceInNoscriptInHead() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errNonSpaceInNoscriptInHead"); + } +} + +void +nsHtml5TreeBuilder::errFooBetweenHeadAndBody(nsIAtom* aName) +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errFooBetweenHeadAndBody", aName); + } +} + +void +nsHtml5TreeBuilder::errStartTagWithoutDoctype() +{ + if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) { + mViewSource->AddErrorToCurrentRun("errStartTagWithoutDoctype"); + } +} + +void +nsHtml5TreeBuilder::errNoSelectInTableScope() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errNoSelectInTableScope"); + } +} + +void +nsHtml5TreeBuilder::errStartSelectWhereEndSelectExpected() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun( + "errStartSelectWhereEndSelectExpected"); + } +} + +void +nsHtml5TreeBuilder::errStartTagWithSelectOpen(nsIAtom* aName) +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errStartTagWithSelectOpen", aName); + } +} + +void +nsHtml5TreeBuilder::errBadStartTagInHead(nsIAtom* aName) +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errBadStartTagInHead2", aName); + } +} + +void +nsHtml5TreeBuilder::errImage() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errImage"); + } +} + +void +nsHtml5TreeBuilder::errIsindex() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errIsindex"); + } +} + +void +nsHtml5TreeBuilder::errFooSeenWhenFooOpen(nsIAtom* aName) +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errFooSeenWhenFooOpen", aName); + } +} + +void +nsHtml5TreeBuilder::errHeadingWhenHeadingOpen() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errHeadingWhenHeadingOpen"); + } +} + +void +nsHtml5TreeBuilder::errFramesetStart() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errFramesetStart"); + } +} + +void +nsHtml5TreeBuilder::errNoCellToClose() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errNoCellToClose"); + } +} + +void +nsHtml5TreeBuilder::errStartTagInTable(nsIAtom* aName) +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errStartTagInTable", aName); + } +} + +void +nsHtml5TreeBuilder::errFormWhenFormOpen() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errFormWhenFormOpen"); + } +} + +void +nsHtml5TreeBuilder::errTableSeenWhileTableOpen() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errTableSeenWhileTableOpen"); + } +} + +void +nsHtml5TreeBuilder::errStartTagInTableBody(nsIAtom* aName) +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errStartTagInTableBody", aName); + } +} + +void +nsHtml5TreeBuilder::errEndTagSeenWithoutDoctype() +{ + if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) { + mViewSource->AddErrorToCurrentRun("errEndTagSeenWithoutDoctype"); + } +} + +void +nsHtml5TreeBuilder::errEndTagAfterBody() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errEndTagAfterBody"); + } +} + +void +nsHtml5TreeBuilder::errEndTagSeenWithSelectOpen(nsIAtom* aName) +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errEndTagSeenWithSelectOpen", + aName); + } +} + +void +nsHtml5TreeBuilder::errGarbageInColgroup() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errGarbageInColgroup"); + } +} + +void +nsHtml5TreeBuilder::errEndTagBr() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errEndTagBr"); + } +} + +void +nsHtml5TreeBuilder::errNoElementToCloseButEndTagSeen(nsIAtom* aName) +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun( + "errNoElementToCloseButEndTagSeen", aName); + } +} + +void +nsHtml5TreeBuilder::errHtmlStartTagInForeignContext(nsIAtom* aName) +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errHtmlStartTagInForeignContext", + aName); + } +} + +void +nsHtml5TreeBuilder::errTableClosedWhileCaptionOpen() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errTableClosedWhileCaptionOpen"); + } +} + +void +nsHtml5TreeBuilder::errNoTableRowToClose() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errNoTableRowToClose"); + } +} + +void +nsHtml5TreeBuilder::errNonSpaceInTable() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errNonSpaceInTable"); + } +} + +void +nsHtml5TreeBuilder::errUnclosedChildrenInRuby() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errUnclosedChildrenInRuby"); + } +} + +void +nsHtml5TreeBuilder::errStartTagSeenWithoutRuby(nsIAtom* aName) +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errStartTagSeenWithoutRuby", + aName); + } +} + +void +nsHtml5TreeBuilder::errSelfClosing() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentSlash("errSelfClosing"); + } +} + +void +nsHtml5TreeBuilder::errNoCheckUnclosedElementsOnStack() +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun( + "errNoCheckUnclosedElementsOnStack"); + } +} + +void +nsHtml5TreeBuilder::errEndTagDidNotMatchCurrentOpenElement(nsIAtom* aName, + nsIAtom* aOther) +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun( + "errEndTagDidNotMatchCurrentOpenElement", aName, aOther); + } +} + +void +nsHtml5TreeBuilder::errEndTagViolatesNestingRules(nsIAtom* aName) +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errEndTagViolatesNestingRules", aName); + } +} + +void +nsHtml5TreeBuilder::errEndWithUnclosedElements(nsIAtom* aName) +{ + if (MOZ_UNLIKELY(mViewSource)) { + mViewSource->AddErrorToCurrentRun("errEndWithUnclosedElements", aName); + } +}