summaryrefslogtreecommitdiff
path: root/Source/WebCore/html/parser/HTMLConstructionSite.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/html/parser/HTMLConstructionSite.cpp')
-rw-r--r--Source/WebCore/html/parser/HTMLConstructionSite.cpp568
1 files changed, 306 insertions, 262 deletions
diff --git a/Source/WebCore/html/parser/HTMLConstructionSite.cpp b/Source/WebCore/html/parser/HTMLConstructionSite.cpp
index 0f0699826..f8dc5a518 100644
--- a/Source/WebCore/html/parser/HTMLConstructionSite.cpp
+++ b/Source/WebCore/html/parser/HTMLConstructionSite.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,6 +28,8 @@
#include "HTMLTreeBuilder.h"
#include "Comment.h"
+#include "CustomElementRegistry.h"
+#include "DOMWindow.h"
#include "DocumentFragment.h"
#include "DocumentType.h"
#include "Frame.h"
@@ -36,42 +38,61 @@
#include "HTMLElementFactory.h"
#include "HTMLFormElement.h"
#include "HTMLHtmlElement.h"
+#include "HTMLImageElement.h"
#include "HTMLOptGroupElement.h"
#include "HTMLOptionElement.h"
#include "HTMLParserIdioms.h"
+#include "HTMLPictureElement.h"
#include "HTMLScriptElement.h"
#include "HTMLTemplateElement.h"
+#include "HTMLUnknownElement.h"
+#include "JSCustomElementInterface.h"
#include "NotImplemented.h"
+#include "SVGElement.h"
#include "Text.h"
namespace WebCore {
using namespace HTMLNames;
-static inline void setAttributes(Element* element, AtomicHTMLToken* token, ParserContentPolicy parserContentPolicy)
+static inline void setAttributes(Element& element, Vector<Attribute>& attributes, ParserContentPolicy parserContentPolicy)
{
if (!scriptingContentIsAllowed(parserContentPolicy))
- element->stripScriptingAttributes(token->attributes());
- element->parserSetAttributes(token->attributes());
+ element.stripScriptingAttributes(attributes);
+ element.parserSetAttributes(attributes);
}
-static bool hasImpliedEndTag(const HTMLStackItem* item)
+static inline void setAttributes(Element& element, AtomicHTMLToken& token, ParserContentPolicy parserContentPolicy)
{
- return item->hasTagName(ddTag)
- || item->hasTagName(dtTag)
- || item->hasTagName(liTag)
- || isHTMLOptionElement(item->node())
- || isHTMLOptGroupElement(item->node())
- || item->hasTagName(pTag)
- || item->hasTagName(rpTag)
- || item->hasTagName(rtTag);
+ setAttributes(element, token.attributes(), parserContentPolicy);
}
-static bool shouldUseLengthLimit(const ContainerNode* node)
+static bool hasImpliedEndTag(const HTMLStackItem& item)
{
- return !node->hasTagName(scriptTag)
- && !node->hasTagName(styleTag)
- && !node->hasTagName(SVGNames::scriptTag);
+ return item.hasTagName(ddTag)
+ || item.hasTagName(dtTag)
+ || item.hasTagName(liTag)
+ || is<HTMLOptionElement>(item.node())
+ || is<HTMLOptGroupElement>(item.node())
+ || item.hasTagName(pTag)
+ || item.hasTagName(rbTag)
+ || item.hasTagName(rpTag)
+ || item.hasTagName(rtTag)
+ || item.hasTagName(rtcTag);
+}
+
+static bool shouldUseLengthLimit(const ContainerNode& node)
+{
+ return !node.hasTagName(scriptTag) && !node.hasTagName(styleTag) && !node.hasTagName(SVGNames::scriptTag);
+}
+
+static inline bool causesFosterParenting(const HTMLStackItem& item)
+{
+ return item.hasTagName(HTMLNames::tableTag)
+ || item.hasTagName(HTMLNames::tbodyTag)
+ || item.hasTagName(HTMLNames::tfootTag)
+ || item.hasTagName(HTMLNames::theadTag)
+ || item.hasTagName(HTMLNames::trTag);
}
static inline bool isAllWhitespace(const String& string)
@@ -81,18 +102,14 @@ static inline bool isAllWhitespace(const String& string)
static inline void insert(HTMLConstructionSiteTask& task)
{
-#if ENABLE(TEMPLATE_ELEMENT)
- if (task.parent->hasTagName(templateTag))
- task.parent = toHTMLTemplateElement(task.parent.get())->content();
-#endif
-
- if (ContainerNode* parent = task.child->parentNode())
- parent->parserRemoveChild(*task.child);
+ if (is<HTMLTemplateElement>(*task.parent))
+ task.parent = &downcast<HTMLTemplateElement>(*task.parent).content();
+ ASSERT(!task.child->parentNode());
if (task.nextChild)
- task.parent->parserInsertBefore(task.child.get(), task.nextChild.get());
+ task.parent->parserInsertBefore(*task.child, *task.nextChild);
else
- task.parent->parserAppendChild(task.child.get());
+ task.parent->parserAppendChild(*task.child);
}
static inline void executeInsertTask(HTMLConstructionSiteTask& task)
@@ -110,27 +127,43 @@ static inline void executeInsertTask(HTMLConstructionSiteTask& task)
static inline void executeReparentTask(HTMLConstructionSiteTask& task)
{
ASSERT(task.operation == HTMLConstructionSiteTask::Reparent);
+ ASSERT(!task.nextChild);
- if (ContainerNode* parent = task.child->parentNode())
+ if (auto* parent = task.child->parentNode())
parent->parserRemoveChild(*task.child);
- task.parent->parserAppendChild(task.child);
+ if (task.child->parentNode())
+ return;
+
+ task.parent->parserAppendChild(*task.child);
}
static inline void executeInsertAlreadyParsedChildTask(HTMLConstructionSiteTask& task)
{
ASSERT(task.operation == HTMLConstructionSiteTask::InsertAlreadyParsedChild);
+ if (ContainerNode* parent = task.child->parentNode())
+ parent->parserRemoveChild(*task.child);
+
+ if (task.child->parentNode())
+ return;
+
+ if (task.nextChild && task.nextChild->parentNode() != task.parent)
+ return;
+
insert(task);
}
-static inline void executeTakeAllChildrenTask(HTMLConstructionSiteTask& task)
+static inline void executeTakeAllChildrenAndReparentTask(HTMLConstructionSiteTask& task)
{
- ASSERT(task.operation == HTMLConstructionSiteTask::TakeAllChildren);
+ ASSERT(task.operation == HTMLConstructionSiteTask::TakeAllChildrenAndReparent);
+ ASSERT(!task.nextChild);
+
+ auto* furthestBlock = task.oldParent();
+ task.parent->takeAllChildrenFrom(furthestBlock);
- task.parent->takeAllChildrenFrom(task.oldParent());
- // Notice that we don't need to manually attach the moved children
- // because takeAllChildrenFrom does that work for us.
+ RELEASE_ASSERT(!task.parent->parentNode());
+ furthestBlock->parserAppendChild(*task.parent);
}
static inline void executeTask(HTMLConstructionSiteTask& task)
@@ -146,86 +179,79 @@ static inline void executeTask(HTMLConstructionSiteTask& task)
case HTMLConstructionSiteTask::Reparent:
executeReparentTask(task);
return;
- case HTMLConstructionSiteTask::TakeAllChildren:
- executeTakeAllChildrenTask(task);
+ case HTMLConstructionSiteTask::TakeAllChildrenAndReparent:
+ executeTakeAllChildrenAndReparentTask(task);
return;
}
ASSERT_NOT_REACHED();
}
-void HTMLConstructionSite::attachLater(ContainerNode* parent, PassRefPtr<Node> prpChild, bool selfClosing)
+void HTMLConstructionSite::attachLater(ContainerNode& parent, Ref<Node>&& child, bool selfClosing)
{
- ASSERT(scriptingContentIsAllowed(m_parserContentPolicy) || !prpChild.get()->isElementNode() || !toScriptElementIfPossible(toElement(prpChild.get())));
- ASSERT(pluginContentIsAllowed(m_parserContentPolicy) || !prpChild->isPluginElement());
-
- HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert);
- task.parent = parent;
- task.child = prpChild;
- task.selfClosing = selfClosing;
+ ASSERT(scriptingContentIsAllowed(m_parserContentPolicy) || !is<Element>(child.get()) || !isScriptElement(downcast<Element>(child.get())));
+ ASSERT(pluginContentIsAllowed(m_parserContentPolicy) || !child->isPluginElement());
if (shouldFosterParent()) {
- fosterParent(task.child);
+ fosterParent(WTFMove(child));
return;
}
+ HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert);
+ task.parent = &parent;
+ task.child = WTFMove(child);
+ task.selfClosing = selfClosing;
+
// Add as a sibling of the parent if we have reached the maximum depth allowed.
if (m_openElements.stackDepth() > m_maximumDOMTreeDepth && task.parent->parentNode())
task.parent = task.parent->parentNode();
ASSERT(task.parent);
- m_taskQueue.append(task);
+ m_taskQueue.append(WTFMove(task));
}
void HTMLConstructionSite::executeQueuedTasks()
{
- const size_t size = m_taskQueue.size();
- if (!size)
+ if (m_taskQueue.isEmpty())
return;
// Copy the task queue into a local variable in case executeTask
// re-enters the parser.
- TaskQueue queue = std::move(m_taskQueue);
+ TaskQueue queue = WTFMove(m_taskQueue);
- for (size_t i = 0; i < size; ++i)
- executeTask(queue[i]);
+ for (auto& task : queue)
+ executeTask(task);
// We might be detached now.
}
HTMLConstructionSite::HTMLConstructionSite(Document& document, ParserContentPolicy parserContentPolicy, unsigned maximumDOMTreeDepth)
- : m_document(&document)
- , m_attachmentRoot(&document)
+ : m_document(document)
+ , m_attachmentRoot(document)
, m_parserContentPolicy(parserContentPolicy)
, m_isParsingFragment(false)
, m_redirectAttachToFosterParent(false)
, m_maximumDOMTreeDepth(maximumDOMTreeDepth)
, m_inQuirksMode(document.inQuirksMode())
{
- ASSERT(m_document->isHTMLDocument() || m_document->isXHTMLDocument());
+ ASSERT(m_document.isHTMLDocument() || m_document.isXHTMLDocument());
}
HTMLConstructionSite::HTMLConstructionSite(DocumentFragment& fragment, ParserContentPolicy parserContentPolicy, unsigned maximumDOMTreeDepth)
- : m_document(&fragment.document())
- , m_attachmentRoot(&fragment)
+ : m_document(fragment.document())
+ , m_attachmentRoot(fragment)
, m_parserContentPolicy(parserContentPolicy)
, m_isParsingFragment(true)
, m_redirectAttachToFosterParent(false)
, m_maximumDOMTreeDepth(maximumDOMTreeDepth)
, m_inQuirksMode(fragment.document().inQuirksMode())
{
- ASSERT(m_document->isHTMLDocument() || m_document->isXHTMLDocument());
+ ASSERT(m_document.isHTMLDocument() || m_document.isXHTMLDocument());
}
HTMLConstructionSite::~HTMLConstructionSite()
{
}
-void HTMLConstructionSite::detach()
-{
- m_document = 0;
- m_attachmentRoot = 0;
-}
-
void HTMLConstructionSite::setForm(HTMLFormElement* form)
{
// This method should only be needed for HTMLTreeBuilder in the fragment case.
@@ -233,70 +259,71 @@ void HTMLConstructionSite::setForm(HTMLFormElement* form)
m_form = form;
}
-PassRefPtr<HTMLFormElement> HTMLConstructionSite::takeForm()
+RefPtr<HTMLFormElement> HTMLConstructionSite::takeForm()
{
- return m_form.release();
+ return WTFMove(m_form);
}
void HTMLConstructionSite::dispatchDocumentElementAvailableIfNeeded()
{
- ASSERT(m_document);
- if (m_document->frame() && !m_isParsingFragment)
- m_document->frame()->injectUserScripts(InjectAtDocumentStart);
+ if (m_isParsingFragment)
+ return;
+
+ if (auto* frame = m_document.frame())
+ frame->injectUserScripts(InjectAtDocumentStart);
}
-void HTMLConstructionSite::insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken&& token)
{
- RefPtr<HTMLHtmlElement> element = HTMLHtmlElement::create(*m_document);
- setAttributes(element.get(), token, m_parserContentPolicy);
- attachLater(m_attachmentRoot, element);
- m_openElements.pushHTMLHtmlElement(HTMLStackItem::create(element, token));
+ auto element = HTMLHtmlElement::create(m_document);
+ setAttributes(element, token, m_parserContentPolicy);
+ attachLater(m_attachmentRoot, element.copyRef());
+ m_openElements.pushHTMLHtmlElement(HTMLStackItem::create(element.copyRef(), WTFMove(token)));
executeQueuedTasks();
element->insertedByParser();
dispatchDocumentElementAvailableIfNeeded();
}
-void HTMLConstructionSite::mergeAttributesFromTokenIntoElement(AtomicHTMLToken* token, Element* element)
+void HTMLConstructionSite::mergeAttributesFromTokenIntoElement(AtomicHTMLToken&& token, Element& element)
{
- if (token->attributes().isEmpty())
+ if (token.attributes().isEmpty())
return;
- for (unsigned i = 0; i < token->attributes().size(); ++i) {
- const Attribute& tokenAttribute = token->attributes().at(i);
- if (!element->elementData() || !element->findAttributeByName(tokenAttribute.name()))
- element->setAttribute(tokenAttribute.name(), tokenAttribute.value());
+ for (auto& tokenAttribute : token.attributes()) {
+ if (!element.elementData() || !element.findAttributeByName(tokenAttribute.name()))
+ element.setAttribute(tokenAttribute.name(), tokenAttribute.value());
}
}
-void HTMLConstructionSite::insertHTMLHtmlStartTagInBody(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertHTMLHtmlStartTagInBody(AtomicHTMLToken&& token)
{
// Fragments do not have a root HTML element, so any additional HTML elements
// encountered during fragment parsing should be ignored.
if (m_isParsingFragment)
return;
- mergeAttributesFromTokenIntoElement(token, m_openElements.htmlElement());
+ mergeAttributesFromTokenIntoElement(WTFMove(token), m_openElements.htmlElement());
}
-void HTMLConstructionSite::insertHTMLBodyStartTagInBody(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertHTMLBodyStartTagInBody(AtomicHTMLToken&& token)
{
- mergeAttributesFromTokenIntoElement(token, m_openElements.bodyElement());
+ mergeAttributesFromTokenIntoElement(WTFMove(token), m_openElements.bodyElement());
}
void HTMLConstructionSite::setDefaultCompatibilityMode()
{
if (m_isParsingFragment)
return;
- if (m_document->isSrcdocDocument())
+ if (m_document.isSrcdocDocument())
return;
- setCompatibilityMode(Document::QuirksMode);
+ setCompatibilityMode(DocumentCompatibilityMode::QuirksMode);
}
-void HTMLConstructionSite::setCompatibilityMode(Document::CompatibilityMode mode)
+void HTMLConstructionSite::setCompatibilityMode(DocumentCompatibilityMode mode)
{
- m_inQuirksMode = (mode == Document::QuirksMode);
- m_document->setCompatibilityMode(mode);
+ m_inQuirksMode = (mode == DocumentCompatibilityMode::QuirksMode);
+ m_document.setCompatibilityMode(mode);
}
void HTMLConstructionSite::setCompatibilityModeFromDoctype(const String& name, const String& publicId, const String& systemId)
@@ -362,15 +389,15 @@ void HTMLConstructionSite::setCompatibilityModeFromDoctype(const String& name, c
|| publicId.startsWith("-//W3C//DTD HTML Experimental 970421//", false)
|| publicId.startsWith("-//W3C//DTD W3 HTML//", false)
|| publicId.startsWith("-//W3O//DTD W3 HTML 3.0//", false)
- || equalIgnoringCase(publicId, "-//W3O//DTD W3 HTML Strict 3.0//EN//")
+ || equalLettersIgnoringASCIICase(publicId, "-//w3o//dtd w3 html strict 3.0//en//")
|| publicId.startsWith("-//WebTechs//DTD Mozilla HTML 2.0//", false)
|| publicId.startsWith("-//WebTechs//DTD Mozilla HTML//", false)
- || equalIgnoringCase(publicId, "-/W3C/DTD HTML 4.0 Transitional/EN")
- || equalIgnoringCase(publicId, "HTML")
- || equalIgnoringCase(systemId, "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd")
+ || equalLettersIgnoringASCIICase(publicId, "-/w3c/dtd html 4.0 transitional/en")
+ || equalLettersIgnoringASCIICase(publicId, "html")
+ || equalLettersIgnoringASCIICase(systemId, "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd")
|| (systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Frameset//", false))
|| (systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Transitional//", false))) {
- setCompatibilityMode(Document::QuirksMode);
+ setCompatibilityMode(DocumentCompatibilityMode::QuirksMode);
return;
}
@@ -379,27 +406,27 @@ void HTMLConstructionSite::setCompatibilityModeFromDoctype(const String& name, c
|| publicId.startsWith("-//W3C//DTD XHTML 1.0 Transitional//", false)
|| (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Frameset//", false))
|| (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Transitional//", false))) {
- setCompatibilityMode(Document::LimitedQuirksMode);
+ setCompatibilityMode(DocumentCompatibilityMode::LimitedQuirksMode);
return;
}
// Otherwise we are No Quirks Mode.
- setCompatibilityMode(Document::NoQuirksMode);
+ setCompatibilityMode(DocumentCompatibilityMode::NoQuirksMode);
}
void HTMLConstructionSite::finishedParsing()
{
- m_document->finishedParsing();
+ m_document.finishedParsing();
}
-void HTMLConstructionSite::insertDoctype(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertDoctype(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::DOCTYPE);
+ ASSERT(token.type() == HTMLToken::DOCTYPE);
+
+ String publicId = token.publicIdentifier();
+ String systemId = token.systemIdentifier();
- const String& publicId = StringImpl::create8BitIfPossible(token->publicIdentifier());
- const String& systemId = StringImpl::create8BitIfPossible(token->systemIdentifier());
- RefPtr<DocumentType> doctype = DocumentType::create(*m_document, token->name(), publicId, systemId);
- attachLater(m_attachmentRoot, doctype.release());
+ attachLater(m_attachmentRoot, DocumentType::create(m_document, token.name(), publicId, systemId));
// DOCTYPE nodes are only processed when parsing fragments w/o contextElements, which
// never occurs. However, if we ever chose to support such, this code is subtly wrong,
@@ -410,70 +437,88 @@ void HTMLConstructionSite::insertDoctype(AtomicHTMLToken* token)
if (m_isParsingFragment)
return;
- if (token->forceQuirks())
- setCompatibilityMode(Document::QuirksMode);
- else {
- setCompatibilityModeFromDoctype(token->name(), publicId, systemId);
- }
+ if (token.forceQuirks())
+ setCompatibilityMode(DocumentCompatibilityMode::QuirksMode);
+ else
+ setCompatibilityModeFromDoctype(token.name(), publicId, systemId);
}
-void HTMLConstructionSite::insertComment(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertComment(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::Comment);
- attachLater(currentNode(), Comment::create(ownerDocumentForCurrentNode(), token->comment()));
+ ASSERT(token.type() == HTMLToken::Comment);
+ attachLater(currentNode(), Comment::create(ownerDocumentForCurrentNode(), token.comment()));
}
-void HTMLConstructionSite::insertCommentOnDocument(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertCommentOnDocument(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::Comment);
- attachLater(m_attachmentRoot, Comment::create(*m_document, token->comment()));
+ ASSERT(token.type() == HTMLToken::Comment);
+ attachLater(m_attachmentRoot, Comment::create(m_document, token.comment()));
}
-void HTMLConstructionSite::insertCommentOnHTMLHtmlElement(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertCommentOnHTMLHtmlElement(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::Comment);
- ContainerNode* parent = m_openElements.rootNode();
- attachLater(parent, Comment::create(parent->document(), token->comment()));
+ ASSERT(token.type() == HTMLToken::Comment);
+ ContainerNode& parent = m_openElements.rootNode();
+ attachLater(parent, Comment::create(parent.document(), token.comment()));
}
-void HTMLConstructionSite::insertHTMLHeadElement(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertHTMLHeadElement(AtomicHTMLToken&& token)
{
ASSERT(!shouldFosterParent());
- m_head = HTMLStackItem::create(createHTMLElement(token), token);
+ m_head = HTMLStackItem::create(createHTMLElement(token), WTFMove(token));
attachLater(currentNode(), m_head->element());
- m_openElements.pushHTMLHeadElement(m_head);
+ m_openElements.pushHTMLHeadElement(*m_head);
}
-void HTMLConstructionSite::insertHTMLBodyElement(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertHTMLBodyElement(AtomicHTMLToken&& token)
{
ASSERT(!shouldFosterParent());
- RefPtr<Element> body = createHTMLElement(token);
- attachLater(currentNode(), body);
- m_openElements.pushHTMLBodyElement(HTMLStackItem::create(body.release(), token));
+ auto body = createHTMLElement(token);
+ attachLater(currentNode(), body.copyRef());
+ m_openElements.pushHTMLBodyElement(HTMLStackItem::create(WTFMove(body), WTFMove(token)));
+}
+
+void HTMLConstructionSite::insertHTMLFormElement(AtomicHTMLToken&& token, bool isDemoted)
+{
+ auto element = createHTMLElement(token);
+ auto& formElement = downcast<HTMLFormElement>(element.get());
+ // If there is no template element on the stack of open elements, set the
+ // form element pointer to point to the element created.
+ if (!openElements().hasTemplateInHTMLScope())
+ m_form = &formElement;
+ formElement.setDemoted(isDemoted);
+ attachLater(currentNode(), formElement);
+ m_openElements.push(HTMLStackItem::create(formElement, WTFMove(token)));
}
-void HTMLConstructionSite::insertHTMLFormElement(AtomicHTMLToken* token, bool isDemoted)
+void HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken&& token)
{
- RefPtr<Element> element = createHTMLElement(token);
- ASSERT(isHTMLFormElement(element.get()));
- RefPtr<HTMLFormElement> form = static_pointer_cast<HTMLFormElement>(element.release());
- if (!insideTemplateElement())
- m_form = form;
- form->setDemoted(isDemoted);
- attachLater(currentNode(), form);
- m_openElements.push(HTMLStackItem::create(form.release(), token));
+ auto element = createHTMLElement(token);
+ attachLater(currentNode(), element.copyRef());
+ m_openElements.push(HTMLStackItem::create(WTFMove(element), WTFMove(token)));
}
-void HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken* token)
+std::unique_ptr<CustomElementConstructionData> HTMLConstructionSite::insertHTMLElementOrFindCustomElementInterface(AtomicHTMLToken&& token)
{
- RefPtr<Element> element = createHTMLElement(token);
- attachLater(currentNode(), element);
- m_openElements.push(HTMLStackItem::create(element.release(), token));
+ JSCustomElementInterface* elementInterface = nullptr;
+ RefPtr<Element> element = createHTMLElementOrFindCustomElementInterface(token, &elementInterface);
+ if (UNLIKELY(elementInterface))
+ return std::make_unique<CustomElementConstructionData>(*elementInterface, token.name(), WTFMove(token.attributes()));
+ attachLater(currentNode(), *element);
+ m_openElements.push(HTMLStackItem::create(element.releaseNonNull(), WTFMove(token)));
+ return nullptr;
}
-void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertCustomElement(Ref<Element>&& element, const AtomicString& localName, Vector<Attribute>&& attributes)
{
- ASSERT(token->type() == HTMLToken::StartTag);
+ setAttributes(element, attributes, m_parserContentPolicy);
+ attachLater(currentNode(), element.copyRef());
+ m_openElements.push(HTMLStackItem::create(WTFMove(element), localName, WTFMove(attributes)));
+}
+
+void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken&& token)
+{
+ ASSERT(token.type() == HTMLToken::StartTag);
// Normally HTMLElementStack is responsible for calling finishParsingChildren,
// but self-closing elements are never in the element stack so the stack
// doesn't get a chance to tell them that we're done parsing their children.
@@ -482,16 +527,17 @@ void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken* token)
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#acknowledge-self-closing-flag
}
-void HTMLConstructionSite::insertFormattingElement(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertFormattingElement(AtomicHTMLToken&& token)
{
// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-stack-of-open-elements
// Possible active formatting elements include:
// a, b, big, code, em, font, i, nobr, s, small, strike, strong, tt, and u.
- insertHTMLElement(token);
- m_activeFormattingElements.append(currentElementRecord()->stackItem());
+ ASSERT(isFormattingTag(token.name()));
+ insertHTMLElement(WTFMove(token));
+ m_activeFormattingElements.append(currentStackItem());
}
-void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken&& token)
{
// http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#already-started
// http://html5.org/specs/dom-parsing.html#dom-range-createcontextualfragment
@@ -500,59 +546,55 @@ void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken* token)
// those flags or effects thereof.
const bool parserInserted = m_parserContentPolicy != AllowScriptingContentAndDoNotMarkAlreadyStarted;
const bool alreadyStarted = m_isParsingFragment && parserInserted;
- RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, ownerDocumentForCurrentNode(), parserInserted, alreadyStarted);
- setAttributes(element.get(), token, m_parserContentPolicy);
+ auto element = HTMLScriptElement::create(scriptTag, ownerDocumentForCurrentNode(), parserInserted, alreadyStarted);
+ setAttributes(element, token, m_parserContentPolicy);
if (scriptingContentIsAllowed(m_parserContentPolicy))
- attachLater(currentNode(), element);
- m_openElements.push(HTMLStackItem::create(element.release(), token));
+ attachLater(currentNode(), element.copyRef());
+ m_openElements.push(HTMLStackItem::create(WTFMove(element), WTFMove(token)));
}
-void HTMLConstructionSite::insertForeignElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
+void HTMLConstructionSite::insertForeignElement(AtomicHTMLToken&& token, const AtomicString& namespaceURI)
{
- ASSERT(token->type() == HTMLToken::StartTag);
+ ASSERT(token.type() == HTMLToken::StartTag);
notImplemented(); // parseError when xmlns or xmlns:xlink are wrong.
- RefPtr<Element> element = createElement(token, namespaceURI);
- if (scriptingContentIsAllowed(m_parserContentPolicy) || !toScriptElementIfPossible(element.get()))
- attachLater(currentNode(), element, token->selfClosing());
- if (!token->selfClosing())
- m_openElements.push(HTMLStackItem::create(element.release(), token, namespaceURI));
+ auto element = createElement(token, namespaceURI);
+ if (scriptingContentIsAllowed(m_parserContentPolicy) || !isScriptElement(element.get()))
+ attachLater(currentNode(), element.copyRef(), token.selfClosing());
+ if (!token.selfClosing())
+ m_openElements.push(HTMLStackItem::create(WTFMove(element), WTFMove(token), namespaceURI));
}
void HTMLConstructionSite::insertTextNode(const String& characters, WhitespaceMode whitespaceMode)
{
HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert);
- task.parent = currentNode();
+ task.parent = &currentNode();
if (shouldFosterParent())
findFosterSite(task);
-#if ENABLE(TEMPLATE_ELEMENT)
- if (task.parent->hasTagName(templateTag))
- task.parent = toHTMLTemplateElement(task.parent.get())->content();
-#endif
+ if (is<HTMLTemplateElement>(*task.parent))
+ task.parent = &downcast<HTMLTemplateElement>(*task.parent).content();
// Strings composed entirely of whitespace are likely to be repeated.
// Turn them into AtomicString so we share a single string for each.
- bool shouldUseAtomicString = whitespaceMode == AllWhitespace
- || (whitespaceMode == WhitespaceUnknown && isAllWhitespace(characters));
+ bool shouldUseAtomicString = whitespaceMode == AllWhitespace || (whitespaceMode == WhitespaceUnknown && isAllWhitespace(characters));
unsigned currentPosition = 0;
- unsigned lengthLimit = shouldUseLengthLimit(task.parent.get()) ? Text::defaultLengthLimit : std::numeric_limits<unsigned>::max();
+ unsigned lengthLimit = shouldUseLengthLimit(*task.parent) ? Text::defaultLengthLimit : std::numeric_limits<unsigned>::max();
// FIXME: Splitting text nodes into smaller chunks contradicts HTML5 spec, but is currently necessary
// for performance, see <https://bugs.webkit.org/show_bug.cgi?id=55898>.
Node* previousChild = task.nextChild ? task.nextChild->previousSibling() : task.parent->lastChild();
- if (previousChild && previousChild->isTextNode()) {
+ if (is<Text>(previousChild)) {
// FIXME: We're only supposed to append to this text node if it
// was the last text node inserted by the parser.
- Text* textNode = toText(previousChild);
- currentPosition = textNode->parserAppendData(characters, 0, lengthLimit);
+ currentPosition = downcast<Text>(*previousChild).parserAppendData(characters, 0, lengthLimit);
}
while (currentPosition < characters.length()) {
- RefPtr<Text> textNode = Text::createWithLengthLimit(task.parent->document(), shouldUseAtomicString ? AtomicString(characters).string() : characters, currentPosition, lengthLimit);
+ auto textNode = Text::createWithLengthLimit(task.parent->document(), shouldUseAtomicString ? AtomicString(characters).string() : characters, currentPosition, lengthLimit);
// If we have a whole string of unbreakable characters the above could lead to an infinite loop. Exceeding the length limit is the lesser evil.
if (!textNode->length()) {
String substring = characters.substring(currentPosition);
@@ -561,7 +603,7 @@ void HTMLConstructionSite::insertTextNode(const String& characters, WhitespaceMo
currentPosition += textNode->length();
ASSERT(currentPosition <= characters.length());
- task.child = textNode.release();
+ task.child = WTFMove(textNode);
executeTask(task);
}
@@ -570,126 +612,141 @@ void HTMLConstructionSite::insertTextNode(const String& characters, WhitespaceMo
void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord& newParent, HTMLElementStack::ElementRecord& child)
{
HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Reparent);
- task.parent = newParent.node();
- task.child = child.element();
- m_taskQueue.append(task);
-}
-
-void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord& newParent, HTMLStackItem& child)
-{
- HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Reparent);
- task.parent = newParent.node();
- task.child = child.element();
- m_taskQueue.append(task);
+ task.parent = &newParent.node();
+ task.child = &child.element();
+ m_taskQueue.append(WTFMove(task));
}
void HTMLConstructionSite::insertAlreadyParsedChild(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& child)
{
- if (newParent.causesFosterParenting()) {
- fosterParent(child.element());
- return;
- }
-
HTMLConstructionSiteTask task(HTMLConstructionSiteTask::InsertAlreadyParsedChild);
- task.parent = newParent.node();
- task.child = child.element();
- m_taskQueue.append(task);
+ if (causesFosterParenting(newParent)) {
+ findFosterSite(task);
+ ASSERT(task.parent);
+ } else
+ task.parent = &newParent.node();
+ task.child = &child.element();
+ m_taskQueue.append(WTFMove(task));
}
-void HTMLConstructionSite::takeAllChildren(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& oldParent)
+void HTMLConstructionSite::takeAllChildrenAndReparent(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& oldParent)
{
- HTMLConstructionSiteTask task(HTMLConstructionSiteTask::TakeAllChildren);
- task.parent = newParent.node();
- task.child = oldParent.node();
- m_taskQueue.append(task);
+ HTMLConstructionSiteTask task(HTMLConstructionSiteTask::TakeAllChildrenAndReparent);
+ task.parent = &newParent.node();
+ task.child = &oldParent.node();
+ m_taskQueue.append(WTFMove(task));
}
-PassRefPtr<Element> HTMLConstructionSite::createElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
+Ref<Element> HTMLConstructionSite::createElement(AtomicHTMLToken& token, const AtomicString& namespaceURI)
{
- QualifiedName tagName(nullAtom, token->name(), namespaceURI);
- RefPtr<Element> element = ownerDocumentForCurrentNode().createElement(tagName, true);
- setAttributes(element.get(), token, m_parserContentPolicy);
- return element.release();
+ QualifiedName tagName(nullAtom, token.name(), namespaceURI);
+ auto element = ownerDocumentForCurrentNode().createElement(tagName, true);
+ setAttributes(element, token, m_parserContentPolicy);
+ return element;
}
inline Document& HTMLConstructionSite::ownerDocumentForCurrentNode()
{
-#if ENABLE(TEMPLATE_ELEMENT)
- if (currentNode()->hasTagName(templateTag))
- return toHTMLTemplateElement(currentElement())->content()->document();
-#endif
- return currentNode()->document();
+ if (is<HTMLTemplateElement>(currentNode()))
+ return downcast<HTMLTemplateElement>(currentNode()).content().document();
+ return currentNode().document();
}
-inline bool HTMLConstructionSite::insideTemplateElement()
+RefPtr<Element> HTMLConstructionSite::createHTMLElementOrFindCustomElementInterface(AtomicHTMLToken& token, JSCustomElementInterface** customElementInterface)
{
- return !ownerDocumentForCurrentNode().frame();
-}
-
-PassRefPtr<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken* token)
-{
- QualifiedName tagName(nullAtom, token->name(), xhtmlNamespaceURI);
+ auto& localName = token.name();
// FIXME: This can't use HTMLConstructionSite::createElement because we
// have to pass the current form element. We should rework form association
// to occur after construction to allow better code sharing here.
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#create-an-element-for-the-token
Document& ownerDocument = ownerDocumentForCurrentNode();
bool insideTemplateElement = !ownerDocument.frame();
- RefPtr<Element> element = HTMLElementFactory::createElement(tagName, ownerDocument, insideTemplateElement ? nullptr : form(), true);
- setAttributes(element.get(), token, m_parserContentPolicy);
+ RefPtr<Element> element = HTMLElementFactory::createKnownElement(localName, ownerDocument, insideTemplateElement ? nullptr : form(), true);
+ if (UNLIKELY(!element)) {
+ auto* window = ownerDocument.domWindow();
+ if (customElementInterface && window) {
+ auto* registry = window->customElementRegistry();
+ if (UNLIKELY(registry)) {
+ if (auto* elementInterface = registry->findInterface(localName)) {
+ *customElementInterface = elementInterface;
+ return nullptr;
+ }
+ }
+ }
+
+ QualifiedName qualifiedName(nullAtom, localName, xhtmlNamespaceURI);
+ if (Document::validateCustomElementName(localName) == CustomElementNameValidationStatus::Valid) {
+ element = HTMLElement::create(qualifiedName, ownerDocument);
+ element->setIsCustomElementUpgradeCandidate();
+ } else
+ element = HTMLUnknownElement::create(qualifiedName, ownerDocument);
+ }
+ ASSERT(element);
+
+ // FIXME: This is a hack to connect images to pictures before the image has
+ // been inserted into the document. It can be removed once asynchronous image
+ // loading is working.
+ if (is<HTMLPictureElement>(currentNode()) && is<HTMLImageElement>(*element))
+ downcast<HTMLImageElement>(*element).setPictureElement(&downcast<HTMLPictureElement>(currentNode()));
+
+ setAttributes(*element, token, m_parserContentPolicy);
ASSERT(element->isHTMLElement());
- return element.release();
+ return element;
+}
+
+Ref<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken& token)
+{
+ RefPtr<Element> element = createHTMLElementOrFindCustomElementInterface(token, nullptr);
+ ASSERT(element);
+ return element.releaseNonNull();
}
-PassRefPtr<HTMLStackItem> HTMLConstructionSite::createElementFromSavedToken(HTMLStackItem* item)
+Ref<HTMLStackItem> HTMLConstructionSite::createElementFromSavedToken(HTMLStackItem& item)
{
- RefPtr<Element> element;
// NOTE: Moving from item -> token -> item copies the Attribute vector twice!
- AtomicHTMLToken fakeToken(HTMLToken::StartTag, item->localName(), item->attributes());
- if (item->namespaceURI() == HTMLNames::xhtmlNamespaceURI)
- element = createHTMLElement(&fakeToken);
- else
- element = createElement(&fakeToken, item->namespaceURI());
- return HTMLStackItem::create(element.release(), &fakeToken, item->namespaceURI());
+ AtomicHTMLToken fakeToken(HTMLToken::StartTag, item.localName(), Vector<Attribute>(item.attributes()));
+ ASSERT(item.namespaceURI() == HTMLNames::xhtmlNamespaceURI);
+ ASSERT(isFormattingTag(item.localName()));
+ return HTMLStackItem::create(createHTMLElement(fakeToken), WTFMove(fakeToken), item.namespaceURI());
}
-bool HTMLConstructionSite::indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const
+std::optional<unsigned> HTMLConstructionSite::indexOfFirstUnopenFormattingElement() const
{
if (m_activeFormattingElements.isEmpty())
- return false;
+ return std::nullopt;
unsigned index = m_activeFormattingElements.size();
do {
--index;
- const HTMLFormattingElementList::Entry& entry = m_activeFormattingElements.at(index);
+ const auto& entry = m_activeFormattingElements.at(index);
if (entry.isMarker() || m_openElements.contains(entry.element())) {
- firstUnopenElementIndex = index + 1;
- return firstUnopenElementIndex < m_activeFormattingElements.size();
+ unsigned firstUnopenElementIndex = index + 1;
+ return firstUnopenElementIndex < m_activeFormattingElements.size() ? firstUnopenElementIndex : std::optional<unsigned>(std::nullopt);
}
} while (index);
- firstUnopenElementIndex = index;
- return true;
+
+ return index;
}
void HTMLConstructionSite::reconstructTheActiveFormattingElements()
{
- unsigned firstUnopenElementIndex;
- if (!indexOfFirstUnopenFormattingElement(firstUnopenElementIndex))
+ std::optional<unsigned> firstUnopenElementIndex = indexOfFirstUnopenFormattingElement();
+ if (!firstUnopenElementIndex)
return;
- unsigned unopenEntryIndex = firstUnopenElementIndex;
- ASSERT(unopenEntryIndex < m_activeFormattingElements.size());
- for (; unopenEntryIndex < m_activeFormattingElements.size(); ++unopenEntryIndex) {
- HTMLFormattingElementList::Entry& unopenedEntry = m_activeFormattingElements.at(unopenEntryIndex);
- RefPtr<HTMLStackItem> reconstructed = createElementFromSavedToken(unopenedEntry.stackItem().get());
+ ASSERT(firstUnopenElementIndex.value() < m_activeFormattingElements.size());
+ for (unsigned unopenEntryIndex = firstUnopenElementIndex.value(); unopenEntryIndex < m_activeFormattingElements.size(); ++unopenEntryIndex) {
+ auto& unopenedEntry = m_activeFormattingElements.at(unopenEntryIndex);
+ ASSERT(unopenedEntry.stackItem());
+ auto reconstructed = createElementFromSavedToken(*unopenedEntry.stackItem());
attachLater(currentNode(), reconstructed->node());
- m_openElements.push(reconstructed);
- unopenedEntry.replaceElement(reconstructed.release());
+ m_openElements.push(reconstructed.copyRef());
+ unopenedEntry.replaceElement(WTFMove(reconstructed));
}
}
void HTMLConstructionSite::generateImpliedEndTagsWithExclusion(const AtomicString& tagName)
{
- while (hasImpliedEndTag(currentStackItem()) && !currentStackItem()->matchesHTMLTag(tagName))
+ while (hasImpliedEndTag(currentStackItem()) && !currentStackItem().matchesHTMLTag(tagName))
m_openElements.pop();
}
@@ -699,60 +756,47 @@ void HTMLConstructionSite::generateImpliedEndTags()
m_openElements.pop();
}
-bool HTMLConstructionSite::inQuirksMode()
-{
- return m_inQuirksMode;
-}
-
void HTMLConstructionSite::findFosterSite(HTMLConstructionSiteTask& task)
{
-#if ENABLE(TEMPLATE_ELEMENT)
// When a node is to be foster parented, the last template element with no table element is below it in the stack of open elements is the foster parent element (NOT the template's parent!)
- HTMLElementStack::ElementRecord* lastTemplateElement = m_openElements.topmost(templateTag.localName());
+ auto* lastTemplateElement = m_openElements.topmost(templateTag.localName());
if (lastTemplateElement && !m_openElements.inTableScope(tableTag)) {
- task.parent = lastTemplateElement->element();
+ task.parent = &lastTemplateElement->element();
return;
}
-#endif
-
- HTMLElementStack::ElementRecord* lastTableElementRecord = m_openElements.topmost(tableTag.localName());
- if (lastTableElementRecord) {
- Element* lastTableElement = lastTableElementRecord->element();
- ContainerNode* parent = lastTableElement->parentNode();
+ if (auto* lastTableElementRecord = m_openElements.topmost(tableTag.localName())) {
+ auto& lastTableElement = lastTableElementRecord->element();
+ auto* parent = lastTableElement.parentNode();
// When parsing HTML fragments, we skip step 4.2 ("Let root be a new html element with no attributes") for efficiency,
// and instead use the DocumentFragment as a root node. So we must treat the root node (DocumentFragment) as if it is a html element here.
- bool parentCanBeFosterParent = parent && (parent->isElementNode() || (m_isParsingFragment && parent == m_openElements.rootNode()));
-#if ENABLE(TEMPLATE_ELEMENT)
- parentCanBeFosterParent = parentCanBeFosterParent || (parent && parent->isDocumentFragment() && toDocumentFragment(parent)->isTemplateContent());
-#endif
+ bool parentCanBeFosterParent = parent && (parent->isElementNode() || (m_isParsingFragment && parent == &m_openElements.rootNode()));
+ parentCanBeFosterParent = parentCanBeFosterParent || (is<DocumentFragment>(parent) && downcast<DocumentFragment>(parent)->isTemplateContent());
if (parentCanBeFosterParent) {
task.parent = parent;
- task.nextChild = lastTableElement;
+ task.nextChild = &lastTableElement;
return;
}
- task.parent = lastTableElementRecord->next()->element();
+ task.parent = &lastTableElementRecord->next()->element();
return;
}
// Fragment case
- task.parent = m_openElements.rootNode(); // DocumentFragment
+ task.parent = &m_openElements.rootNode(); // DocumentFragment
}
bool HTMLConstructionSite::shouldFosterParent() const
{
- return m_redirectAttachToFosterParent
- && currentStackItem()->isElementNode()
- && currentStackItem()->causesFosterParenting();
+ return m_redirectAttachToFosterParent && causesFosterParenting(currentStackItem());
}
-void HTMLConstructionSite::fosterParent(PassRefPtr<Node> node)
+void HTMLConstructionSite::fosterParent(Ref<Node>&& node)
{
HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert);
findFosterSite(task);
- task.child = node;
+ task.child = WTFMove(node);
ASSERT(task.parent);
- m_taskQueue.append(task);
+ m_taskQueue.append(WTFMove(task));
}
}