Bug 959150 part 4 - Avoid using tree ops when parsing with nsHtml5StringParser. r=smaug.

This commit is contained in:
Henri Sivonen 2014-03-05 21:38:50 +02:00
Родитель 5979d40c36
Коммит 0ad400f8e1
16 изменённых файлов: 636 добавлений и 301 удалений

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

@ -5137,6 +5137,9 @@ public abstract class TreeBuilder<T> implements TokenHandler,
checkAttributes(attributes, "http://www.w3.org/1999/xhtml");
// ]NOCPP]
// This method can't be called for custom elements
HtmlAttributes clone = attributes.cloneAttributes(null);
// Attributes must not be read after calling createElement, because
// createElement may delete attributes in C++.
T elt = createElement("http://www.w3.org/1999/xhtml", elementName.name, attributes);
StackNode<T> current = stack[currentPtr];
if (current.isFosterParenting()) {
@ -5145,7 +5148,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
} else {
appendElement(elt, current.node);
}
StackNode<T> node = new StackNode<T>(elementName, elt, attributes.cloneAttributes(null)
StackNode<T> node = new StackNode<T>(elementName, elt, clone
// [NOCPP[
, errorHandler == null ? null : new TaintableLocatorImpl(tokenizer)
// ]NOCPP]
@ -5211,6 +5214,13 @@ public abstract class TreeBuilder<T> implements TokenHandler,
popName = checkPopName(popName);
}
// ]NOCPP]
boolean markAsHtmlIntegrationPoint = false;
if (ElementName.ANNOTATION_XML == elementName
&& annotationXmlEncodingPermitsHtml(attributes)) {
markAsHtmlIntegrationPoint = true;
}
// Attributes must not be read after calling createElement(), since
// createElement may delete the object in C++.
T elt = createElement("http://www.w3.org/1998/Math/MathML", popName,
attributes);
StackNode<T> current = stack[currentPtr];
@ -5220,11 +5230,6 @@ public abstract class TreeBuilder<T> implements TokenHandler,
} else {
appendElement(elt, current.node);
}
boolean markAsHtmlIntegrationPoint = false;
if (ElementName.ANNOTATION_XML == elementName
&& annotationXmlEncodingPermitsHtml(attributes)) {
markAsHtmlIntegrationPoint = true;
}
StackNode<T> node = new StackNode<T>(elementName, elt, popName,
markAsHtmlIntegrationPoint
// [NOCPP[

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

@ -30,6 +30,7 @@ EXPORTS += [
'nsHtml5Module.h',
'nsHtml5NamedCharacters.h',
'nsHtml5NamedCharactersAccel.h',
'nsHtml5OplessBuilder.h',
'nsHtml5OwningUTF16Buffer.h',
'nsHtml5Parser.h',
'nsHtml5PendingNotification.h',
@ -63,6 +64,7 @@ UNIFIED_SOURCES += [
'nsHtml5Module.cpp',
'nsHtml5NamedCharacters.cpp',
'nsHtml5NamedCharactersAccel.cpp',
'nsHtml5OplessBuilder.cpp',
'nsHtml5OwningUTF16Buffer.cpp',
'nsHtml5Parser.cpp',
'nsHtml5PlainTextUtils.cpp',

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

@ -6,9 +6,10 @@
#include "nsHtml5DocumentBuilder.h"
#include "nsIStyleSheetLinkingElement.h"
#include "nsStyleLinkElement.h"
#include "nsScriptLoader.h"
#include "mozilla/css/Loader.h"
#include "nsIDocShell.h"
#include "nsIHTMLDocument.h"
NS_IMPL_CYCLE_COLLECTION_INHERITED_1(nsHtml5DocumentBuilder, nsContentSink,
mOwnedElements)
@ -19,15 +20,125 @@ NS_INTERFACE_MAP_END_INHERITING(nsContentSink)
NS_IMPL_ADDREF_INHERITED(nsHtml5DocumentBuilder, nsContentSink)
NS_IMPL_RELEASE_INHERITED(nsHtml5DocumentBuilder, nsContentSink)
void
nsHtml5DocumentBuilder::DropHeldElements()
nsHtml5DocumentBuilder::nsHtml5DocumentBuilder(bool aRunsToCompletion)
{
mScriptLoader = nullptr;
mDocument = nullptr;
mNodeInfoManager = nullptr;
mCSSLoader = nullptr;
mDocumentURI = nullptr;
mDocShell = nullptr;
mOwnedElements.Clear();
mRunsToCompletion = aRunsToCompletion;
}
nsresult
nsHtml5DocumentBuilder::Init(nsIDocument* aDoc,
nsIURI* aURI,
nsISupports* aContainer,
nsIChannel* aChannel)
{
return nsContentSink::Init(aDoc, aURI, aContainer, aChannel);
}
nsHtml5DocumentBuilder::~nsHtml5DocumentBuilder()
{
}
nsresult
nsHtml5DocumentBuilder::MarkAsBroken(nsresult aReason)
{
mBroken = aReason;
return aReason;
}
void
nsHtml5DocumentBuilder::SetDocumentCharsetAndSource(nsACString& aCharset, int32_t aCharsetSource)
{
if (mDocument) {
mDocument->SetDocumentCharacterSetSource(aCharsetSource);
mDocument->SetDocumentCharacterSet(aCharset);
}
}
void
nsHtml5DocumentBuilder::UpdateStyleSheet(nsIContent* aElement)
{
// Break out of the doc update created by Flush() to zap a runnable
// waiting to call UpdateStyleSheet without the right observer
EndDocUpdate();
if (MOZ_UNLIKELY(!mParser)) {
// EndDocUpdate ran stuff that called nsIParser::Terminate()
return;
}
nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aElement));
NS_ASSERTION(ssle, "Node didn't QI to style.");
ssle->SetEnableUpdates(true);
bool willNotify;
bool isAlternate;
nsresult rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
&willNotify,
&isAlternate);
if (NS_SUCCEEDED(rv) && willNotify && !isAlternate && !mRunsToCompletion) {
++mPendingSheetCount;
mScriptLoader->AddExecuteBlocker();
}
if (aElement->IsHTML(nsGkAtoms::link)) {
// look for <link rel="next" href="url">
nsAutoString relVal;
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal);
if (!relVal.IsEmpty()) {
uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(relVal);
bool hasPrefetch = linkTypes & nsStyleLinkElement::ePREFETCH;
if (hasPrefetch || (linkTypes & nsStyleLinkElement::eNEXT)) {
nsAutoString hrefVal;
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
if (!hrefVal.IsEmpty()) {
PrefetchHref(hrefVal, aElement, hasPrefetch);
}
}
if (linkTypes & nsStyleLinkElement::eDNS_PREFETCH) {
nsAutoString hrefVal;
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
if (!hrefVal.IsEmpty()) {
PrefetchDNS(hrefVal);
}
}
}
}
// Re-open update
BeginDocUpdate();
}
void
nsHtml5DocumentBuilder::SetDocumentMode(nsHtml5DocumentMode m)
{
nsCompatibility mode = eCompatibility_NavQuirks;
switch (m) {
case STANDARDS_MODE:
mode = eCompatibility_FullStandards;
break;
case ALMOST_STANDARDS_MODE:
mode = eCompatibility_AlmostStandards;
break;
case QUIRKS_MODE:
mode = eCompatibility_NavQuirks;
break;
}
nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(mDocument);
NS_ASSERTION(htmlDocument, "Document didn't QI into HTML document.");
htmlDocument->SetCompatibilityMode(mode);
}
// nsContentSink overrides
void
nsHtml5DocumentBuilder::UpdateChildCounts()
{
// No-op
}
nsresult
nsHtml5DocumentBuilder::FlushTags()
{
return NS_OK;
}

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

@ -8,6 +8,9 @@
#define nsHtml5DocumentBuilder_h
#include "nsHtml5PendingNotification.h"
#include "nsContentSink.h"
#include "nsHtml5DocumentMode.h"
#include "nsIDocument.h"
typedef nsIContent* nsIContentPtr;
@ -92,7 +95,8 @@ public:
mFlushState = eInDocUpdate;
}
void DropHeldElements();
nsresult Init(nsIDocument* aDoc, nsIURI* aURI,
nsISupports* aContainer, nsIChannel* aChannel);
// Getters and setters for fields from nsContentSink
nsIDocument* GetDocument() {
@ -102,7 +106,54 @@ public:
return mNodeInfoManager;
}
virtual bool BelongsToStringParser() = 0;
/**
* Marks this parser as broken and tells the stream parser (if any) to
* terminate.
*
* @return aReason for convenience
*/
virtual nsresult MarkAsBroken(nsresult aReason);
/**
* Checks if this parser is broken. Returns a non-NS_OK (i.e. non-0)
* value if broken.
*/
inline nsresult IsBroken() {
return mBroken;
}
inline void BeginDocUpdate() {
NS_PRECONDITION(mFlushState == eInFlush, "Tried to double-open update.");
NS_PRECONDITION(mParser, "Started update without parser.");
mFlushState = eInDocUpdate;
mDocument->BeginUpdate(UPDATE_CONTENT_MODEL);
}
inline void EndDocUpdate() {
NS_PRECONDITION(mFlushState != eNotifying, "mFlushState out of sync");
if (mFlushState == eInDocUpdate) {
FlushPendingAppendNotifications();
mFlushState = eInFlush;
mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
}
}
void SetDocumentCharsetAndSource(nsACString& aCharset, int32_t aCharsetSource);
/**
* Sets up style sheet load / parse
*/
void UpdateStyleSheet(nsIContent* aElement);
void SetDocumentMode(nsHtml5DocumentMode m);
void SetNodeInfoManager(nsNodeInfoManager* aManager) {
mNodeInfoManager = aManager;
}
// nsContentSink methods
virtual void UpdateChildCounts();
virtual nsresult FlushTags();
protected:
inline void SetAppendBatchCapacity(uint32_t aCapacity)
@ -110,11 +161,26 @@ protected:
mElementsSeenInThisAppendBatch.SetCapacity(aCapacity);
}
nsHtml5DocumentBuilder(bool aRunsToCompletion);
virtual ~nsHtml5DocumentBuilder();
private:
nsTArray<nsHtml5PendingNotification> mPendingNotifications;
nsTArray<nsCOMPtr<nsIContent> > mOwnedElements;
nsTArray<nsIContentPtr> mElementsSeenInThisAppendBatch;
protected:
nsTArray<nsCOMPtr<nsIContent> > mOwnedElements;
/**
* Non-NS_OK if this parser should refuse to process any more input.
* For example, the parser needs to be marked as broken if it drops some
* input due to a memory allocation failure. In such a case, the whole
* parser needs to be marked as broken, because some input has been lost
* and parsing more input could lead to a DOM where pieces of HTML source
* that weren't supposed to become scripts become scripts.
*
* Since NS_OK is actually 0, zeroing operator new takes care of
* initializing this.
*/
nsresult mBroken;
eHtml5FlushState mFlushState;
};

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

@ -0,0 +1,49 @@
/* -*- 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 "nsHtml5OplessBuilder.h"
#include "nsScriptLoader.h"
#include "mozilla/css/Loader.h"
#include "nsIDocShell.h"
#include "nsIHTMLDocument.h"
nsHtml5OplessBuilder::nsHtml5OplessBuilder()
: nsHtml5DocumentBuilder(true)
{
}
nsHtml5OplessBuilder::~nsHtml5OplessBuilder()
{
}
void
nsHtml5OplessBuilder::Start()
{
mFlushState = eInFlush;
BeginDocUpdate();
}
void
nsHtml5OplessBuilder::Finish()
{
EndDocUpdate();
DropParserAndPerfHint();
mScriptLoader = nullptr;
mDocument = nullptr;
mNodeInfoManager = nullptr;
mCSSLoader = nullptr;
mDocumentURI = nullptr;
mDocShell = nullptr;
mOwnedElements.Clear();
mFlushState = eNotFlushing;
}
void
nsHtml5OplessBuilder::SetParser(nsParserBase* aParser)
{
mParser = aParser;
}

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

@ -0,0 +1,26 @@
/* -*- 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/. */
#ifndef nsHtml5OplessBuilder_h
#define nsHtml5OplessBuilder_h
#include "nsHtml5DocumentBuilder.h"
class nsParserBase;
class nsHtml5OplessBuilder : public nsHtml5DocumentBuilder
{
public:
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
nsHtml5OplessBuilder();
~nsHtml5OplessBuilder();
void Start();
void Finish();
void SetParser(nsParserBase* aParser);
};
#endif // nsHtml5OplessBuilder_h

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

@ -14,8 +14,8 @@
NS_IMPL_ISUPPORTS0(nsHtml5StringParser)
nsHtml5StringParser::nsHtml5StringParser()
: mExecutor(new nsHtml5TreeOpExecutor(true))
, mTreeBuilder(new nsHtml5TreeBuilder(mExecutor, nullptr))
: mBuilder(new nsHtml5OplessBuilder())
, mTreeBuilder(new nsHtml5TreeBuilder(mBuilder))
, mTokenizer(new nsHtml5Tokenizer(mTreeBuilder, false))
{
MOZ_COUNT_CTOR(nsHtml5StringParser);
@ -42,10 +42,9 @@ nsHtml5StringParser::ParseFragment(const nsAString& aSourceBuffer,
nsIURI* uri = doc->GetDocumentURI();
NS_ENSURE_TRUE(uri, NS_ERROR_NOT_AVAILABLE);
nsIContent* target = aTargetNode;
mTreeBuilder->setFragmentContext(aContextLocalName,
aContextNamespace,
&target,
aTargetNode,
aQuirks);
#ifdef DEBUG
@ -61,8 +60,7 @@ nsHtml5StringParser::ParseFragment(const nsAString& aSourceBuffer,
mTreeBuilder->SetPreventScriptExecution(aPreventScriptExecution);
Tokenize(aSourceBuffer, doc, true);
return NS_OK;
return Tokenize(aSourceBuffer, doc, true);
}
nsresult
@ -82,28 +80,28 @@ nsHtml5StringParser::ParseDocument(const nsAString& aSourceBuffer,
mTreeBuilder->SetPreventScriptExecution(true);
Tokenize(aSourceBuffer, aTargetDoc, aScriptingEnabledForNoscriptParsing);
return NS_OK;
return Tokenize(aSourceBuffer, aTargetDoc, aScriptingEnabledForNoscriptParsing);
}
void
nsresult
nsHtml5StringParser::Tokenize(const nsAString& aSourceBuffer,
nsIDocument* aDocument,
bool aScriptingEnabledForNoscriptParsing) {
nsIURI* uri = aDocument->GetDocumentURI();
mExecutor->Init(aDocument, uri, nullptr, nullptr);
mBuilder->Init(aDocument, uri, nullptr, nullptr);
mExecutor->SetParser(this);
mExecutor->SetNodeInfoManager(aDocument->NodeInfoManager());
mBuilder->SetParser(this);
mBuilder->SetNodeInfoManager(aDocument->NodeInfoManager());
// Mark the parser as *not* broken by passing NS_OK
nsresult rv = mBuilder->MarkAsBroken(NS_OK);
NS_PRECONDITION(!mExecutor->HasStarted(),
"Tried to start parse without initializing the parser.");
mTreeBuilder->setScriptingEnabled(aScriptingEnabledForNoscriptParsing);
mTreeBuilder->setIsSrcdocDocument(aDocument->IsSrcdocDocument());
mBuilder->Start();
mTokenizer->start();
mExecutor->Start(); // Don't call WillBuildModel in fragment case
if (!aSourceBuffer.IsEmpty()) {
bool lastWasCR = false;
nsHtml5DependentUTF16Buffer buffer(aSourceBuffer);
@ -112,25 +110,15 @@ nsHtml5StringParser::Tokenize(const nsAString& aSourceBuffer,
lastWasCR = false;
if (buffer.hasMore()) {
lastWasCR = mTokenizer->tokenizeBuffer(&buffer);
if (mTreeBuilder->HasScript()) {
// If we come here, we are in createContextualFragment() or in the
// upcoming document.parse(). It's unclear if it's really necessary
// to flush here, but let's do so for consistency with other flushes
// to avoid different code paths on the executor side.
mTreeBuilder->Flush(); // Move ops to the executor
mExecutor->FlushDocumentWrite(); // run the ops
if (NS_FAILED(rv = mBuilder->IsBroken())) {
break;
}
}
}
}
mTokenizer->eof();
mTreeBuilder->StreamEnded();
mTreeBuilder->Flush();
mExecutor->FlushDocumentWrite();
mTokenizer->end();
mExecutor->DropParserAndPerfHint();
mExecutor->DropHeldElements();
mTreeBuilder->DropHandles();
mBuilder->Finish();
mAtomTable.Clear();
mExecutor->Reset();
return rv;
}

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

@ -8,7 +8,7 @@
#include "nsHtml5AtomTable.h"
#include "nsParserBase.h"
class nsHtml5TreeOpExecutor;
class nsHtml5OplessBuilder;
class nsHtml5TreeBuilder;
class nsHtml5Tokenizer;
class nsIContent;
@ -58,14 +58,14 @@ class nsHtml5StringParser : public nsParserBase
private:
void Tokenize(const nsAString& aSourceBuffer,
nsIDocument* aDocument,
bool aScriptingEnabledForNoscriptParsing);
nsresult Tokenize(const nsAString& aSourceBuffer,
nsIDocument* aDocument,
bool aScriptingEnabledForNoscriptParsing);
/**
* The tree operation executor
*/
nsRefPtr<nsHtml5TreeOpExecutor> mExecutor;
nsRefPtr<nsHtml5OplessBuilder> mBuilder;
/**
* The HTML5 tree builder

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

@ -54,6 +54,7 @@
#include "nsHtml5ViewSourceUtils.h"
#include "mozilla/Likely.h"
#include "nsIContentHandle.h"
#include "nsHtml5OplessBuilder.h"
#include "nsHtml5Tokenizer.h"
#include "nsHtml5MetaScanner.h"
@ -3899,6 +3900,7 @@ nsHtml5TreeBuilder::appendToCurrentNodeAndPushFormElementMayFoster(nsHtml5HtmlAt
void
nsHtml5TreeBuilder::appendToCurrentNodeAndPushFormattingElementMayFoster(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes)
{
nsHtml5HtmlAttributes* clone = attributes->cloneAttributes(nullptr);
nsIContentHandle* elt = createElement(kNameSpaceID_XHTML, elementName->name, attributes);
nsHtml5StackNode* current = stack[currentPtr];
if (current->isFosterParenting()) {
@ -3907,7 +3909,7 @@ nsHtml5TreeBuilder::appendToCurrentNodeAndPushFormattingElementMayFoster(nsHtml5
} else {
appendElement(elt, current->node);
}
nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt, attributes->cloneAttributes(nullptr));
nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt, clone);
push(node);
append(node);
node->retain();
@ -3945,6 +3947,10 @@ void
nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFosterMathML(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes)
{
nsIAtom* popName = elementName->name;
bool markAsHtmlIntegrationPoint = false;
if (nsHtml5ElementName::ELT_ANNOTATION_XML == elementName && annotationXmlEncodingPermitsHtml(attributes)) {
markAsHtmlIntegrationPoint = true;
}
nsIContentHandle* elt = createElement(kNameSpaceID_MathML, popName, attributes);
nsHtml5StackNode* current = stack[currentPtr];
if (current->isFosterParenting()) {
@ -3953,10 +3959,6 @@ nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFosterMathML(nsHtml5Elem
} else {
appendElement(elt, current->node);
}
bool markAsHtmlIntegrationPoint = false;
if (nsHtml5ElementName::ELT_ANNOTATION_XML == elementName && annotationXmlEncodingPermitsHtml(attributes)) {
markAsHtmlIntegrationPoint = true;
}
nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt, popName, markAsHtmlIntegrationPoint);
push(node);
}

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

@ -55,6 +55,7 @@
#include "nsHtml5ViewSourceUtils.h"
#include "mozilla/Likely.h"
#include "nsIContentHandle.h"
#include "nsHtml5OplessBuilder.h"
class nsHtml5StreamParser;

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

@ -13,6 +13,27 @@
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)
@ -20,6 +41,7 @@ nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink,
, contextNode(nullptr)
, formPointer(nullptr)
, headPointer(nullptr)
, mBuilder(nullptr)
, mViewSource(nullptr)
, mOpSink(aOpSink)
, mHandles(new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH])
@ -51,6 +73,20 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName, nsHtml5Htm
aNamespace == kNameSpaceID_MathML,
"Bogus namespace.");
if (mBuilder) {
nsCOMPtr<nsIAtom> name = nsHtml5TreeOperation::Reget(aName);
nsIContent* elem =
nsHtml5TreeOperation::CreateElement(aNamespace,
name,
aAttributes,
mozilla::dom::FROM_PARSER_FRAGMENT,
mBuilder);
if (aAttributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
delete aAttributes;
}
return elem;
}
nsIContentHandle* content = AllocateContentHandle();
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed.");
@ -214,9 +250,14 @@ nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName, nsHtml5Htm
{
nsIContentHandle* content = createElement(aNamespace, aName, aAttributes);
if (aFormElement) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpSetFormElement, content, aFormElement);
if (mBuilder) {
nsHtml5TreeOperation::SetFormElement(static_cast<nsIContent*>(content),
static_cast<nsIContent*>(aFormElement));
} else {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpSetFormElement, content, aFormElement);
}
}
return content;
}
@ -225,9 +266,17 @@ nsIContentHandle*
nsHtml5TreeBuilder::createHtmlElementSetAsRoot(nsHtml5HtmlAttributes* aAttributes)
{
nsIContentHandle* content = createElement(kNameSpaceID_XHTML, nsHtml5Atoms::html, aAttributes);
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpAppendToDocument, content);
if (mBuilder) {
nsresult rv = nsHtml5TreeOperation::AppendToDocument(static_cast<nsIContent*>(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;
}
@ -236,6 +285,12 @@ nsHtml5TreeBuilder::detachFromParent(nsIContentHandle* aElement)
{
NS_PRECONDITION(aElement, "Null element");
if (mBuilder) {
nsHtml5TreeOperation::Detach(static_cast<nsIContent*>(aElement),
mBuilder);
return;
}
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpDetach, aElement);
@ -249,6 +304,17 @@ nsHtml5TreeBuilder::appendElement(nsIContentHandle* aChild, nsIContentHandle* aP
if (deepTreeSurrogateParent) {
return;
}
if (mBuilder) {
nsresult rv = nsHtml5TreeOperation::Append(static_cast<nsIContent*>(aChild),
static_cast<nsIContent*>(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);
@ -260,6 +326,17 @@ nsHtml5TreeBuilder::appendChildrenToNewParent(nsIContentHandle* aOldParent, nsIC
NS_PRECONDITION(aOldParent, "Null old parent");
NS_PRECONDITION(aNewParent, "Null new parent");
if (mBuilder) {
nsresult rv = nsHtml5TreeOperation::AppendChildrenToNewParent(
static_cast<nsIContent*>(aOldParent),
static_cast<nsIContent*>(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);
@ -271,6 +348,20 @@ nsHtml5TreeBuilder::insertFosterParentedCharacters(char16_t* aBuffer, int32_t aS
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<nsIContent*>(aStackParent),
aBuffer, // XXX aStart always ignored???
aLength,
static_cast<nsIContent*>(aTable),
mBuilder);
if (NS_FAILED(rv)) {
MarkAsBrokenAndRequestSuspension(rv);
}
return;
}
char16_t* bufferCopy = new char16_t[aLength];
memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t));
@ -287,6 +378,18 @@ nsHtml5TreeBuilder::insertFosterParentedChild(nsIContentHandle* aChild, nsIConte
NS_PRECONDITION(aTable, "Null table");
NS_PRECONDITION(aStackParent, "Null stack parent");
if (mBuilder) {
nsresult rv = nsHtml5TreeOperation::FosterParent(
static_cast<nsIContent*>(aChild),
static_cast<nsIContent*>(aStackParent),
static_cast<nsIContent*>(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);
@ -297,6 +400,20 @@ nsHtml5TreeBuilder::appendCharacters(nsIContentHandle* aParent, char16_t* aBuffe
{
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<nsIContent*>(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));
@ -312,6 +429,16 @@ nsHtml5TreeBuilder::appendIsindexPrompt(nsIContentHandle* aParent)
{
NS_PRECONDITION(aParent, "Null parent");
if (mBuilder) {
nsresult rv = nsHtml5TreeOperation::AppendIsindexPrompt(
static_cast<nsIContent*>(aParent),
mBuilder);
if (NS_FAILED(rv)) {
MarkAsBrokenAndRequestSuspension(rv);
}
return;
}
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpAppendIsindexPrompt, aParent);
@ -322,10 +449,24 @@ nsHtml5TreeBuilder::appendComment(nsIContentHandle* aParent, char16_t* aBuffer,
{
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<nsIContent*>(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));
@ -338,6 +479,18 @@ 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));
@ -356,6 +509,18 @@ nsHtml5TreeBuilder::addAttributesToElement(nsIContentHandle* aElement, nsHtml5Ht
if (aAttributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
return;
}
if (mBuilder) {
nsresult rv = nsHtml5TreeOperation::AddAttributes(
static_cast<nsIContent*>(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);
@ -366,6 +531,11 @@ nsHtml5TreeBuilder::markMalformedIfScript(nsIContentHandle* aElement)
{
NS_PRECONDITION(aElement, "Null element");
if (mBuilder) {
// XXX innerHTML
return;
}
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpMarkMalformedIfScript, aElement);
@ -395,6 +565,19 @@ nsHtml5TreeBuilder::appendDoctypeToDocument(nsIAtom* aName, nsString* aPublicId,
{
NS_PRECONDITION(aName, "Null name");
if (mBuilder) {
nsCOMPtr<nsIAtom> 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);
@ -442,6 +625,10 @@ nsHtml5TreeBuilder::elementPushed(int32_t aNamespace, nsIAtom* aName, nsIContent
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);
@ -453,15 +640,27 @@ nsHtml5TreeBuilder::elementPushed(int32_t aNamespace, nsIAtom* aName, nsIContent
// 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.
mOpQueue.AppendElement()->Init(eTreeOpFlushPendingAppendNotifications);
if (mBuilder) {
mBuilder->FlushPendingAppendNotifications();
} else {
mOpQueue.AppendElement()->Init(eTreeOpFlushPendingAppendNotifications);
}
}
if (mBuilder) {
nsHtml5TreeOperation::DoneCreatingElement(static_cast<nsIContent*>(aElement));
} else {
mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement);
}
mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement);
return;
}
if (aName == nsHtml5Atoms::audio ||
aName == nsHtml5Atoms::video ||
aName == nsHtml5Atoms::menuitem) {
mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement);
if (mBuilder) {
nsHtml5TreeOperation::DoneCreatingElement(static_cast<nsIContent*>(aElement));
} else {
mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement);
}
return;
}
}
@ -481,9 +680,16 @@ nsHtml5TreeBuilder::elementPopped(int32_t aNamespace, nsIAtom* aName, nsIContent
// we now have only SVG and HTML
if (aName == nsHtml5Atoms::script) {
if (mPreventScriptExecution) {
if (mBuilder) {
nsHtml5TreeOperation::PreventScriptExecution(static_cast<nsIContent*>(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.");
@ -500,18 +706,34 @@ nsHtml5TreeBuilder::elementPopped(int32_t aNamespace, nsIAtom* aName, nsIContent
return;
}
if (aName == nsHtml5Atoms::title) {
if (mBuilder) {
nsHtml5TreeOperation::DoneAddingChildren(static_cast<nsIContent*>(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<nsIContent*>(aElement));
return;
}
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpUpdateStyleSheet, aElement);
return;
}
if (aNamespace == kNameSpaceID_SVG) {
if (mBuilder) {
// XXX innerHTML
// is this ever needed for the on-the-main-thread case
return;
}
if (aName == nsHtml5Atoms::svg) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed.");
@ -525,6 +747,10 @@ nsHtml5TreeBuilder::elementPopped(int32_t aNamespace, nsIAtom* aName, nsIContent
// XXX expose ElementName group here and do switch
if (aName == nsHtml5Atoms::object ||
aName == nsHtml5Atoms::applet) {
if (mBuilder) {
nsHtml5TreeOperation::DoneAddingChildren(static_cast<nsIContent*>(aElement), mBuilder);
return;
}
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpDoneAddingChildren, aElement);
@ -536,16 +762,24 @@ nsHtml5TreeBuilder::elementPopped(int32_t aNamespace, nsIAtom* aName, nsIContent
// 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.
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpFlushPendingAppendNotifications);
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<nsIContent*>(aElement), mBuilder);
return;
}
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpDoneAddingChildren, aElement);
return;
}
if (aName == nsHtml5Atoms::meta && !fragment) {
if (aName == nsHtml5Atoms::meta && !fragment && !mBuilder) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpProcessMeta, aElement);
@ -571,6 +805,10 @@ nsHtml5TreeBuilder::accumulateCharacters(const char16_t* aBuf, int32_t aStart, i
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];
@ -595,6 +833,10 @@ nsHtml5TreeBuilder::HasScript()
bool
nsHtml5TreeBuilder::Flush(bool aDiscretionary)
{
if (MOZ_UNLIKELY(mBuilder)) {
MOZ_ASSUME_UNREACHABLE("Must never flush with builder.");
return false;
}
if (!aDiscretionary ||
!(charBufferLen &&
currentPtr >= 0 &&
@ -621,6 +863,10 @@ nsHtml5TreeBuilder::Flush(bool aDiscretionary)
void
nsHtml5TreeBuilder::FlushLoads()
{
if (MOZ_UNLIKELY(mBuilder)) {
MOZ_ASSUME_UNREACHABLE("Must never flush loads with builder.");
return;
}
if (!mSpeculativeLoadQueue.IsEmpty()) {
mSpeculativeLoadStage->MoveSpeculativeLoadsFrom(mSpeculativeLoadQueue);
}
@ -630,7 +876,9 @@ void
nsHtml5TreeBuilder::SetDocumentCharset(nsACString& aCharset,
int32_t aCharsetSource)
{
if (mSpeculativeLoadStage) {
if (mBuilder) {
mBuilder->SetDocumentCharsetAndSource(aCharset, aCharsetSource);
} else if (mSpeculativeLoadStage) {
mSpeculativeLoadQueue.AppendElement()->InitSetDocumentCharset(
aCharset, aCharsetSource);
} else {
@ -642,16 +890,11 @@ nsHtml5TreeBuilder::SetDocumentCharset(nsACString& aCharset,
void
nsHtml5TreeBuilder::StreamEnded()
{
// The fragment mode calls DidBuildModel from nsHtml5Parser.
// Letting DidBuildModel be called from the executor in the fragment case
// confuses the EndLoad logic of nsHTMLDocument, since nsHTMLDocument
// thinks it is dealing with document.written content as opposed to
// innerHTML content.
if (!fragment) {
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed.");
treeOp->Init(eTreeOpStreamEnded);
}
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
@ -659,6 +902,10 @@ 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,
@ -672,12 +919,20 @@ 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);
@ -686,6 +941,7 @@ nsHtml5TreeBuilder::AddSnapshotToScript(nsAHtml5TreeBuilderState* aSnapshot, int
void
nsHtml5TreeBuilder::DropHandles()
{
MOZ_ASSERT(!mBuilder, "Must not drop handles with builder.");
mOldHandles.Clear();
mHandlesUsed = 0;
}
@ -693,6 +949,10 @@ nsHtml5TreeBuilder::DropHandles()
void
nsHtml5TreeBuilder::MarkAsBroken()
{
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(eTreeOpMarkAsBroken);
}
@ -700,6 +960,7 @@ nsHtml5TreeBuilder::MarkAsBroken()
void
nsHtml5TreeBuilder::StartPlainTextViewSource(const nsAutoString& aTitle)
{
MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
startTag(nsHtml5ElementName::ELT_TITLE,
nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES,
false);
@ -726,6 +987,7 @@ nsHtml5TreeBuilder::StartPlainTextViewSource(const nsAutoString& aTitle)
void
nsHtml5TreeBuilder::StartPlainText()
{
MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
startTag(nsHtml5ElementName::ELT_LINK,
nsHtml5PlainTextUtils::NewLinkAttributes(),
false);
@ -736,6 +998,7 @@ nsHtml5TreeBuilder::StartPlainText()
void
nsHtml5TreeBuilder::StartPlainTextBody()
{
MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
startTag(nsHtml5ElementName::ELT_PRE,
nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES,
false);
@ -746,6 +1009,10 @@ nsHtml5TreeBuilder::StartPlainTextBody()
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);
@ -754,6 +1021,9 @@ nsHtml5TreeBuilder::documentMode(nsHtml5DocumentMode m)
nsIContentHandle*
nsHtml5TreeBuilder::getDocumentFragmentForTemplate(nsIContentHandle* aTemplate)
{
if (mBuilder) {
return nsHtml5TreeOperation::GetDocumentFragmentForTemplate(static_cast<nsIContent*>(aTemplate));
}
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
NS_ASSERTION(treeOp, "Tree op allocation failed.");
nsIContentHandle* fragHandle = AllocateContentHandle();
@ -764,15 +1034,16 @@ nsHtml5TreeBuilder::getDocumentFragmentForTemplate(nsIContentHandle* aTemplate)
nsIContentHandle*
nsHtml5TreeBuilder::getFormPointerForContext(nsIContentHandle* aContext)
{
MOZ_ASSERT(mBuilder, "Must have builder.");
if (!aContext) {
return nullptr;
}
MOZ_ASSERT(NS_IsMainThread());
// aContext must always be a handle to an element that already exists
// in the document. It must never be an empty handle.
nsIContent* contextNode = *(static_cast<nsIContent**>(aContext));
// aContext must always be an element that already exists
// in the document.
nsIContent* contextNode = static_cast<nsIContent*>(aContext);
nsIContent* currentAncestor = contextNode;
// We traverse the ancestors of the context node to find the nearest
@ -790,9 +1061,7 @@ nsHtml5TreeBuilder::getFormPointerForContext(nsIContentHandle* aContext)
return nullptr;
}
nsIContentHandle* formPointer = AllocateContentHandle();
*(static_cast<nsIContent**>(formPointer)) = nearestForm;
return formPointer;
return nearestForm;
}
// Error reporting
@ -800,6 +1069,7 @@ nsHtml5TreeBuilder::getFormPointerForContext(nsIContentHandle* aContext)
void
nsHtml5TreeBuilder::EnableViewSource(nsHtml5Highlighter* aHighlighter)
{
MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
mViewSource = aHighlighter;
}

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

@ -5,6 +5,11 @@
#define NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH 512
private:
nsHtml5OplessBuilder* mBuilder;
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// If mBuilder is not null, the tree op machinery is not in use and
// the fields below aren't in use, either.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
nsHtml5Highlighter* mViewSource;
nsTArray<nsHtml5TreeOperation> mOpQueue;
nsTArray<nsHtml5SpeculativeLoad> mSpeculativeLoadQueue;
@ -13,7 +18,6 @@
int32_t mHandlesUsed;
nsTArray<nsAutoArrayPtr<nsIContent*> > mOldHandles;
nsHtml5TreeOpStage* mSpeculativeLoadStage;
nsIContent** mDeepTreeSurrogateParent;
bool mCurrentHtmlScriptIsAsyncOrDefer;
bool mPreventScriptExecution;
#ifdef DEBUG
@ -60,8 +64,16 @@
accumulateCharacters(aBuf, aStart, aLength);
}
void MarkAsBrokenAndRequestSuspension(nsresult aRv)
{
mBuilder->MarkAsBroken(aRv);
requestSuspension();
}
public:
nsHtml5TreeBuilder(nsHtml5OplessBuilder* aBuilder);
nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink,
nsHtml5TreeOpStage* aStage);

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

@ -13,8 +13,6 @@
#include "nsIMarkupDocumentViewer.h"
#include "nsIContentViewer.h"
#include "nsIDocShellTreeItem.h"
#include "nsIStyleSheetLinkingElement.h"
#include "nsStyleLinkElement.h"
#include "nsIDocShell.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptSecurityManager.h"
@ -62,10 +60,10 @@ class nsHtml5ExecutorReflusher : public nsRunnable
static mozilla::LinkedList<nsHtml5TreeOpExecutor>* gBackgroundFlushList = nullptr;
static nsITimer* gFlushTimer = nullptr;
nsHtml5TreeOpExecutor::nsHtml5TreeOpExecutor(bool aRunsToCompletion)
: mPreloadedURLs(23) // Mean # of preloadable resources per page on dmoz
nsHtml5TreeOpExecutor::nsHtml5TreeOpExecutor()
: nsHtml5DocumentBuilder(false)
, mPreloadedURLs(23) // Mean # of preloadable resources per page on dmoz
{
mRunsToCompletion = aRunsToCompletion;
// zeroing operator new for everything else
}
@ -210,34 +208,16 @@ nsHtml5TreeOpExecutor::FlushPendingNotifications(mozFlushType aType)
}
}
void
nsHtml5TreeOpExecutor::SetDocumentCharsetAndSource(nsACString& aCharset, int32_t aCharsetSource)
{
if (mDocument) {
mDocument->SetDocumentCharacterSetSource(aCharsetSource);
mDocument->SetDocumentCharacterSet(aCharset);
}
}
nsISupports*
nsHtml5TreeOpExecutor::GetTarget()
{
return mDocument;
}
// nsContentSink overrides
void
nsHtml5TreeOpExecutor::UpdateChildCounts()
{
// No-op
}
nsresult
nsHtml5TreeOpExecutor::MarkAsBroken(nsresult aReason)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(!mRunsToCompletion, "Fragment parsers can't be broken!");
mBroken = aReason;
if (mStreamParser) {
mStreamParser->Terminate();
@ -255,12 +235,6 @@ nsHtml5TreeOpExecutor::MarkAsBroken(nsresult aReason)
return aReason;
}
nsresult
nsHtml5TreeOpExecutor::FlushTags()
{
return NS_OK;
}
void
FlushTimerCallback(nsITimer* aTimer, void* aClosure)
{
@ -303,61 +277,6 @@ nsHtml5TreeOpExecutor::ContinueInterruptedParsingAsync()
}
}
void
nsHtml5TreeOpExecutor::UpdateStyleSheet(nsIContent* aElement)
{
// Break out of the doc update created by Flush() to zap a runnable
// waiting to call UpdateStyleSheet without the right observer
EndDocUpdate();
if (MOZ_UNLIKELY(!mParser)) {
// EndDocUpdate ran stuff that called nsIParser::Terminate()
return;
}
nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aElement));
NS_ASSERTION(ssle, "Node didn't QI to style.");
ssle->SetEnableUpdates(true);
bool willNotify;
bool isAlternate;
nsresult rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
&willNotify,
&isAlternate);
if (NS_SUCCEEDED(rv) && willNotify && !isAlternate && !mRunsToCompletion) {
++mPendingSheetCount;
mScriptLoader->AddExecuteBlocker();
}
if (aElement->IsHTML(nsGkAtoms::link)) {
// look for <link rel="next" href="url">
nsAutoString relVal;
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal);
if (!relVal.IsEmpty()) {
uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(relVal);
bool hasPrefetch = linkTypes & nsStyleLinkElement::ePREFETCH;
if (hasPrefetch || (linkTypes & nsStyleLinkElement::eNEXT)) {
nsAutoString hrefVal;
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
if (!hrefVal.IsEmpty()) {
PrefetchHref(hrefVal, aElement, hasPrefetch);
}
}
if (linkTypes & nsStyleLinkElement::eDNS_PREFETCH) {
nsAutoString hrefVal;
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
if (!hrefVal.IsEmpty()) {
PrefetchDNS(hrefVal);
}
}
}
}
// Re-open update
BeginDocUpdate();
}
void
nsHtml5TreeOpExecutor::FlushSpeculativeLoads()
{
@ -665,26 +584,6 @@ nsHtml5TreeOpExecutor::IsScriptEnabled()
ScriptAllowed(globalObject->GetGlobalJSObject());
}
void
nsHtml5TreeOpExecutor::SetDocumentMode(nsHtml5DocumentMode m)
{
nsCompatibility mode = eCompatibility_NavQuirks;
switch (m) {
case STANDARDS_MODE:
mode = eCompatibility_FullStandards;
break;
case ALMOST_STANDARDS_MODE:
mode = eCompatibility_AlmostStandards;
break;
case QUIRKS_MODE:
mode = eCompatibility_NavQuirks;
break;
}
nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(mDocument);
NS_ASSERTION(htmlDocument, "Document didn't QI into HTML document.");
htmlDocument->SetCompatibilityMode(mode);
}
void
nsHtml5TreeOpExecutor::StartLayout() {
if (mLayoutStarted || !mDocument) {
@ -767,15 +666,6 @@ nsHtml5TreeOpExecutor::RunScript(nsIContent* aScriptElement)
}
}
nsresult
nsHtml5TreeOpExecutor::Init(nsIDocument* aDoc,
nsIURI* aURI,
nsISupports* aContainer,
nsIChannel* aChannel)
{
return nsContentSink::Init(aDoc, aURI, aContainer, aChannel);
}
void
nsHtml5TreeOpExecutor::Start()
{
@ -882,19 +772,6 @@ nsHtml5TreeOpExecutor::GetParser()
return static_cast<nsHtml5Parser*>(mParser.get());
}
void
nsHtml5TreeOpExecutor::Reset()
{
MOZ_ASSERT(mRunsToCompletion);
DropHeldElements();
mOpQueue.Clear();
mStarted = false;
mFlushState = eNotFlushing;
mRunFlushLoopOnStack = false;
MOZ_ASSERT(!mReadingFromStage);
MOZ_ASSERT(NS_SUCCEEDED(mBroken));
}
void
nsHtml5TreeOpExecutor::MoveOpsFrom(nsTArray<nsHtml5TreeOperation>& aOpQueue)
{

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

@ -80,19 +80,6 @@ class nsHtml5TreeOpExecutor : public nsHtml5DocumentBuilder,
bool mCallContinueInterruptedParsingIfEnabled;
/**
* Non-NS_OK if this parser should refuse to process any more input.
* For example, the parser needs to be marked as broken if it drops some
* input due to a memory allocation failure. In such a case, the whole
* parser needs to be marked as broken, because some input has been lost
* and parsing more input could lead to a DOM where pieces of HTML source
* that weren't supposed to become scripts become scripts.
*
* Since NS_OK is actually 0, zeroing operator new takes care of
* initializing this.
*/
nsresult mBroken;
/**
* Whether this executor has already complained about matters related
* to character encoding declarations.
@ -101,7 +88,7 @@ class nsHtml5TreeOpExecutor : public nsHtml5DocumentBuilder,
public:
nsHtml5TreeOpExecutor(bool aRunsToCompletion = false);
nsHtml5TreeOpExecutor();
virtual ~nsHtml5TreeOpExecutor();
// nsIContentSink
@ -154,16 +141,8 @@ class nsHtml5TreeOpExecutor : public nsHtml5DocumentBuilder,
*/
virtual nsISupports *GetTarget();
// nsContentSink methods
virtual void UpdateChildCounts();
virtual nsresult FlushTags();
virtual void ContinueInterruptedParsingAsync();
/**
* Sets up style sheet load / parse
*/
void UpdateStyleSheet(nsIContent* aElement);
// XXX Does anyone need this?
nsIDocShell* GetDocShell() {
return mDocShell;
@ -172,14 +151,8 @@ class nsHtml5TreeOpExecutor : public nsHtml5DocumentBuilder,
bool IsScriptExecuting() {
return IsScriptExecutingImpl();
}
void SetNodeInfoManager(nsNodeInfoManager* aManager) {
mNodeInfoManager = aManager;
}
// Not from interface
void SetDocumentCharsetAndSource(nsACString& aCharset, int32_t aCharsetSource);
// Not from interface
void SetStreamParser(nsHtml5StreamParser* aStreamParser) {
mStreamParser = aStreamParser;
@ -189,50 +162,10 @@ class nsHtml5TreeOpExecutor : public nsHtml5DocumentBuilder,
bool IsScriptEnabled();
bool BelongsToStringParser() {
return mRunsToCompletion;
}
virtual nsresult MarkAsBroken(nsresult aReason);
/**
* Marks this parser as broken and tells the stream parser (if any) to
* terminate.
*
* @return aReason for convenience
*/
nsresult MarkAsBroken(nsresult aReason);
/**
* Checks if this parser is broken. Returns a non-NS_OK (i.e. non-0)
* value if broken.
*/
inline nsresult IsBroken() {
return mBroken;
}
inline void BeginDocUpdate() {
NS_PRECONDITION(mFlushState == eInFlush, "Tried to double-open update.");
NS_PRECONDITION(mParser, "Started update without parser.");
mFlushState = eInDocUpdate;
mDocument->BeginUpdate(UPDATE_CONTENT_MODEL);
}
inline void EndDocUpdate() {
NS_PRECONDITION(mFlushState != eNotifying, "mFlushState out of sync");
if (mFlushState == eInDocUpdate) {
FlushPendingAppendNotifications();
mFlushState = eInFlush;
mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
}
}
void StartLayout();
void SetDocumentMode(nsHtml5DocumentMode m);
nsresult Init(nsIDocument* aDoc, nsIURI* aURI,
nsISupports* aContainer, nsIChannel* aChannel);
void FlushSpeculativeLoads();
void RunFlushLoop();
@ -273,8 +206,6 @@ class nsHtml5TreeOpExecutor : public nsHtml5DocumentBuilder,
void RunScript(nsIContent* aScriptElement);
void Reset();
/**
* Flush the operations from the tree operations from the argument
* queue unconditionally. (This is for the main thread case.)

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

@ -344,7 +344,7 @@ nsIContent*
nsHtml5TreeOperation::CreateElement(int32_t aNs,
nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes,
bool aFromNetwork,
mozilla::dom::FromParser aFromParser,
nsHtml5DocumentBuilder* aBuilder)
{
bool isKeygen = (aName == nsHtml5Atoms::keygen && aNs == kNameSpaceID_XHTML);
@ -358,11 +358,7 @@ nsHtml5TreeOperation::CreateElement(int32_t aNs,
NS_ASSERTION(nodeInfo, "Got null nodeinfo.");
NS_NewElement(getter_AddRefs(newContent),
nodeInfo.forget(),
(aFromNetwork ?
dom::FROM_PARSER_NETWORK
: (aBuilder->BelongsToStringParser() ?
dom::FROM_PARSER_FRAGMENT :
dom::FROM_PARSER_DOCUMENT_WRITE)));
aFromParser);
NS_ASSERTION(newContent, "Element creation created null pointer.");
aBuilder->HoldElement(newContent);
@ -406,11 +402,7 @@ nsHtml5TreeOperation::CreateElement(int32_t aNs,
nsCOMPtr<nsINodeInfo> ni = optionNodeInfo;
NS_NewElement(getter_AddRefs(optionElt),
ni.forget(),
(aFromNetwork ?
dom::FROM_PARSER_NETWORK
: (aBuilder->BelongsToStringParser() ?
dom::FROM_PARSER_FRAGMENT :
dom::FROM_PARSER_DOCUMENT_WRITE)));
aFromParser);
nsRefPtr<nsTextNode> optionText =
new nsTextNode(aBuilder->GetNodeInfoManager());
(void) optionText->SetText(theContent[i], false);
@ -674,7 +666,9 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
*target = CreateElement(ns,
name,
attributes,
mOpCode == eTreeOpCreateElementNetwork,
mOpCode == eTreeOpCreateElementNetwork ?
dom::FROM_PARSER_NETWORK :
dom::FROM_PARSER_DOCUMENT_WRITE,
aBuilder);
return NS_OK;
}

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

@ -8,6 +8,7 @@
#include "nsHtml5DocumentMode.h"
#include "nsHtml5HtmlAttributes.h"
#include "nsXPCOMStrings.h"
#include "mozilla/dom/FromParser.h"
class nsIContent;
class nsHtml5TreeOpExecutor;
@ -146,7 +147,7 @@ class nsHtml5TreeOperation {
static nsIContent* CreateElement(int32_t aNs,
nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes,
bool aFromNetwork,
mozilla::dom::FromParser aFromParser,
nsHtml5DocumentBuilder* aBuilder);
static void SetFormElement(nsIContent* aNode, nsIContent* aParent);