diff options
Diffstat (limited to 'Source/WebCore/html/parser/HTMLTreeBuilder.cpp')
-rw-r--r-- | Source/WebCore/html/parser/HTMLTreeBuilder.cpp | 2499 |
1 files changed, 1159 insertions, 1340 deletions
diff --git a/Source/WebCore/html/parser/HTMLTreeBuilder.cpp b/Source/WebCore/html/parser/HTMLTreeBuilder.cpp index 46b3baf47..4b22f4f8f 100644 --- a/Source/WebCore/html/parser/HTMLTreeBuilder.cpp +++ b/Source/WebCore/html/parser/HTMLTreeBuilder.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 @@ -30,48 +30,42 @@ #include "DocumentFragment.h" #include "HTMLDocument.h" #include "HTMLDocumentParser.h" +#include "HTMLFormControlElement.h" #include "HTMLFormElement.h" #include "HTMLOptGroupElement.h" #include "HTMLOptionElement.h" #include "HTMLParserIdioms.h" +#include "HTMLScriptElement.h" #include "HTMLTableElement.h" -#include "HTMLTemplateElement.h" +#include "JSCustomElementInterface.h" #include "LocalizedStrings.h" #include "NotImplemented.h" +#include "SVGScriptElement.h" #include "XLinkNames.h" #include "XMLNSNames.h" #include "XMLNames.h" -#include <wtf/MainThread.h> +#include <wtf/NeverDestroyed.h> #include <wtf/unicode/CharacterNames.h> -// FIXME: Extract the following iOS-specific code into a separate file. -#if PLATFORM(IOS) -#include "SoftLinking.h" - -#ifdef __has_include -#if __has_include(<DataDetectorsCore/DDDFACache.h>) -#include <DataDetectorsCore/DDDFACache.h> -#else -typedef void* DDDFACacheRef; -#endif - -#if __has_include(<DataDetectorsCore/DDDFAScanner.h>) -#include <DataDetectorsCore/DDDFAScanner.h> -#else -typedef void* DDDFAScannerRef; -#endif -#endif - -SOFT_LINK_PRIVATE_FRAMEWORK_OPTIONAL(DataDetectorsCore) -SOFT_LINK(DataDetectorsCore, DDDFACacheCreateFromFramework, DDDFACacheRef, (), ()) -SOFT_LINK(DataDetectorsCore, DDDFAScannerCreateFromCache, DDDFAScannerRef, (DDDFACacheRef cache), (cache)) -SOFT_LINK(DataDetectorsCore, DDDFAScannerFirstResultInUnicharArray, Boolean, (DDDFAScannerRef scanner, const UniChar* str, unsigned length, int* startPos, int* endPos), (scanner, str, length, startPos, endPos)) +#if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS) +#include "TelephoneNumberDetector.h" #endif namespace WebCore { using namespace HTMLNames; +CustomElementConstructionData::CustomElementConstructionData(Ref<JSCustomElementInterface>&& customElementInterface, const AtomicString& name, Vector<Attribute>&& attributes) + : elementInterface(WTFMove(customElementInterface)) + , name(name) + , attributes(WTFMove(attributes)) +{ +} + +CustomElementConstructionData::~CustomElementConstructionData() +{ +} + namespace { inline bool isHTMLSpaceOrReplacementCharacter(UChar character) @@ -81,9 +75,9 @@ inline bool isHTMLSpaceOrReplacementCharacter(UChar character) } -static TextPosition uninitializedPositionValue1() +static inline TextPosition uninitializedPositionValue1() { - return TextPosition(OrdinalNumber::fromOneBasedInt(-1), OrdinalNumber::first()); + return TextPosition(OrdinalNumber::fromOneBasedInt(-1), OrdinalNumber()); } static inline bool isAllWhitespace(const String& string) @@ -108,9 +102,7 @@ static bool isNumberedHeaderTag(const AtomicString& tagName) static bool isCaptionColOrColgroupTag(const AtomicString& tagName) { - return tagName == captionTag - || tagName == colTag - || tagName == colgroupTag; + return tagName == captionTag || tagName == colTag || tagName == colgroupTag; } static bool isTableCellContextTag(const AtomicString& tagName) @@ -120,9 +112,7 @@ static bool isTableCellContextTag(const AtomicString& tagName) static bool isTableBodyContextTag(const AtomicString& tagName) { - return tagName == tbodyTag - || tagName == tfootTag - || tagName == theadTag; + return tagName == tbodyTag || tagName == tfootTag || tagName == theadTag; } static bool isNonAnchorNonNobrFormattingTag(const AtomicString& tagName) @@ -143,31 +133,27 @@ static bool isNonAnchorNonNobrFormattingTag(const AtomicString& tagName) static bool isNonAnchorFormattingTag(const AtomicString& tagName) { - return tagName == nobrTag - || isNonAnchorNonNobrFormattingTag(tagName); + return tagName == nobrTag || isNonAnchorNonNobrFormattingTag(tagName); } -// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#formatting -static bool isFormattingTag(const AtomicString& tagName) +// https://html.spec.whatwg.org/multipage/syntax.html#formatting +bool HTMLConstructionSite::isFormattingTag(const AtomicString& tagName) { return tagName == aTag || isNonAnchorFormattingTag(tagName); } class HTMLTreeBuilder::ExternalCharacterTokenBuffer { - WTF_MAKE_NONCOPYABLE(ExternalCharacterTokenBuffer); public: - explicit ExternalCharacterTokenBuffer(AtomicHTMLToken* token) - : m_current(token->characters()) - , m_end(m_current + token->charactersLength()) - , m_isAll8BitData(token->isAll8BitData()) + explicit ExternalCharacterTokenBuffer(AtomicHTMLToken& token) + : m_text(token.characters(), token.charactersLength()) + , m_isAll8BitData(token.charactersIsAll8BitData()) { ASSERT(!isEmpty()); } explicit ExternalCharacterTokenBuffer(const String& string) - : m_current(string.deprecatedCharacters()) - , m_end(m_current + string.length()) - , m_isAll8BitData(string.length() && string.is8Bit()) + : m_text(string) + , m_isAll8BitData(m_text.is8Bit()) { ASSERT(!isEmpty()); } @@ -177,15 +163,15 @@ public: ASSERT(isEmpty()); } - bool isEmpty() const { return m_current == m_end; } + bool isEmpty() const { return m_text.isEmpty(); } bool isAll8BitData() const { return m_isAll8BitData; } void skipAtMostOneLeadingNewline() { ASSERT(!isEmpty()); - if (*m_current == '\n') - ++m_current; + if (m_text[0] == '\n') + m_text = m_text.substring(1); } void skipLeadingWhitespace() @@ -205,246 +191,240 @@ public: String takeRemaining() { - ASSERT(!isEmpty()); - const UChar* start = m_current; - m_current = m_end; - size_t length = m_current - start; - - if (isAll8BitData()) - return String::make8BitFrom16BitSource(start, length); - - return String(start, length); + String result = makeString(m_text); + m_text = StringView(); + return result; } void giveRemainingTo(StringBuilder& recipient) { - recipient.append(m_current, m_end - m_current); - m_current = m_end; + recipient.append(m_text); + m_text = StringView(); } String takeRemainingWhitespace() { ASSERT(!isEmpty()); - Vector<UChar> whitespace; + Vector<LChar, 8> whitespace; do { - UChar cc = *m_current++; - if (isHTMLSpace(cc)) - whitespace.append(cc); - } while (m_current < m_end); + UChar character = m_text[0]; + if (isHTMLSpace(character)) + whitespace.append(character); + m_text = m_text.substring(1); + } while (!m_text.isEmpty()); + // Returning the null string when there aren't any whitespace // characters is slightly cleaner semantically because we don't want // to insert a text node (as opposed to inserting an empty text node). if (whitespace.isEmpty()) return String(); - return String::adopt(whitespace); + + return String::adopt(WTFMove(whitespace)); } private: - template<bool characterPredicate(UChar)> - void skipLeading() + template<bool characterPredicate(UChar)> void skipLeading() { ASSERT(!isEmpty()); - while (characterPredicate(*m_current)) { - if (++m_current == m_end) + while (characterPredicate(m_text[0])) { + m_text = m_text.substring(1); + if (m_text.isEmpty()) return; } } - template<bool characterPredicate(UChar)> - String takeLeading() + template<bool characterPredicate(UChar)> String takeLeading() { ASSERT(!isEmpty()); - const UChar* start = m_current; + StringView start = m_text; skipLeading<characterPredicate>(); - if (start == m_current) + if (start.length() == m_text.length()) return String(); - if (isAll8BitData()) - return String::make8BitFrom16BitSource(start, m_current - start); - return String(start, m_current - start); + return makeString(start.substring(0, start.length() - m_text.length())); } - const UChar* m_current; - const UChar* m_end; + String makeString(StringView stringView) const + { + if (stringView.is8Bit() || !isAll8BitData()) + return stringView.toString(); + return String::make8BitFrom16BitSource(stringView.characters16(), stringView.length()); + } + + StringView m_text; bool m_isAll8BitData; }; +inline bool HTMLTreeBuilder::isParsingTemplateContents() const +{ + return m_tree.openElements().hasTemplateInHTMLScope(); +} + +inline bool HTMLTreeBuilder::isParsingFragmentOrTemplateContents() const +{ + return isParsingFragment() || isParsingTemplateContents(); +} HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser& parser, HTMLDocument& document, ParserContentPolicy parserContentPolicy, const HTMLParserOptions& options) - : m_framesetOk(true) -#ifndef NDEBUG - , m_isAttached(true) -#endif + : m_parser(parser) + , m_options(options) , m_tree(document, parserContentPolicy, options.maximumDOMTreeDepth) - , m_insertionMode(InsertionMode::Initial) - , m_originalInsertionMode(InsertionMode::Initial) - , m_shouldSkipLeadingNewline(false) - , m_parser(parser) , m_scriptToProcessStartPosition(uninitializedPositionValue1()) - , m_options(options) { +#if !ASSERT_DISABLED + m_destructionProhibited = false; +#endif } -// FIXME: Member variables should be grouped into self-initializing structs to -// minimize code duplication between these constructors. -HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser& parser, DocumentFragment& fragment, Element* contextElement, ParserContentPolicy parserContentPolicy, const HTMLParserOptions& options) - : m_framesetOk(true) -#ifndef NDEBUG - , m_isAttached(true) -#endif +HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser& parser, DocumentFragment& fragment, Element& contextElement, ParserContentPolicy parserContentPolicy, const HTMLParserOptions& options) + : m_parser(parser) + , m_options(options) , m_fragmentContext(fragment, contextElement) , m_tree(fragment, parserContentPolicy, options.maximumDOMTreeDepth) - , m_insertionMode(InsertionMode::Initial) - , m_originalInsertionMode(InsertionMode::Initial) - , m_shouldSkipLeadingNewline(false) - , m_parser(parser) , m_scriptToProcessStartPosition(uninitializedPositionValue1()) - , m_options(options) { ASSERT(isMainThread()); - // FIXME: This assertion will become invalid if <http://webkit.org/b/60316> is fixed. - ASSERT(contextElement); - if (contextElement) { - // Steps 4.2-4.6 of the HTML5 Fragment Case parsing algorithm: - // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#fragment-case - // For efficiency, we skip step 4.2 ("Let root be a new html element with no attributes") - // and instead use the DocumentFragment as a root node. - m_tree.openElements()->pushRootNode(HTMLStackItem::create(&fragment, HTMLStackItem::ItemForDocumentFragmentNode)); - -#if ENABLE(TEMPLATE_ELEMENT) - if (contextElement->hasTagName(templateTag)) - m_templateInsertionModes.append(InsertionMode::TemplateContents); -#endif - resetInsertionModeAppropriately(); - m_tree.setForm(!contextElement || isHTMLFormElement(contextElement) ? toHTMLFormElement(contextElement) : HTMLFormElement::findClosestFormAncestor(*contextElement)); - } -} + // https://html.spec.whatwg.org/multipage/syntax.html#parsing-html-fragments + // For efficiency, we skip step 5 ("Let root be a new html element with no attributes") and instead use the DocumentFragment as a root node. + m_tree.openElements().pushRootNode(HTMLStackItem::create(fragment)); -HTMLTreeBuilder::~HTMLTreeBuilder() -{ -} + if (contextElement.hasTagName(templateTag)) + m_templateInsertionModes.append(InsertionMode::TemplateContents); -void HTMLTreeBuilder::detach() -{ -#ifndef NDEBUG - // This call makes little sense in fragment mode, but for consistency - // DocumentParser expects detach() to always be called before it's destroyed. - m_isAttached = false; + resetInsertionModeAppropriately(); + + m_tree.setForm(is<HTMLFormElement>(contextElement) ? &downcast<HTMLFormElement>(contextElement) : HTMLFormElement::findClosestFormAncestor(contextElement)); + +#if !ASSERT_DISABLED + m_destructionProhibited = false; #endif - // HTMLConstructionSite might be on the callstack when detach() is called - // otherwise we'd just call m_tree.clear() here instead. - m_tree.detach(); } HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext() - : m_fragment(0) - , m_contextElement(0) { } -HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext(DocumentFragment& fragment, Element* contextElement) +HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext(DocumentFragment& fragment, Element& contextElement) : m_fragment(&fragment) - , m_contextElement(contextElement) { ASSERT(!fragment.hasChildNodes()); + m_contextElementStackItem = HTMLStackItem::create(contextElement); +} + +inline Element& HTMLTreeBuilder::FragmentParsingContext::contextElement() const +{ + return contextElementStackItem().element(); } -HTMLTreeBuilder::FragmentParsingContext::~FragmentParsingContext() +inline HTMLStackItem& HTMLTreeBuilder::FragmentParsingContext::contextElementStackItem() const { + ASSERT(m_fragment); + return *m_contextElementStackItem; } -PassRefPtr<Element> HTMLTreeBuilder::takeScriptToProcess(TextPosition& scriptStartPosition) +RefPtr<ScriptElement> HTMLTreeBuilder::takeScriptToProcess(TextPosition& scriptStartPosition) { - ASSERT(m_scriptToProcess); + ASSERT(!m_destroyed); + + if (!m_scriptToProcess) + return nullptr; + // Unpause ourselves, callers may pause us again when processing the script. - // The HTML5 spec is written as though scripts are executed inside the tree - // builder. We pause the parser to exit the tree builder, and then resume - // before running scripts. + // The HTML5 spec is written as though scripts are executed inside the tree builder. + // We pause the parser to exit the tree builder, and then resume before running scripts. scriptStartPosition = m_scriptToProcessStartPosition; m_scriptToProcessStartPosition = uninitializedPositionValue1(); - return m_scriptToProcess.release(); + return WTFMove(m_scriptToProcess); } -void HTMLTreeBuilder::constructTree(AtomicHTMLToken* token) +void HTMLTreeBuilder::constructTree(AtomicHTMLToken&& token) { +#if !ASSERT_DISABLED + ASSERT(!m_destroyed); + ASSERT(!m_destructionProhibited); + m_destructionProhibited = true; +#endif + if (shouldProcessTokenInForeignContent(token)) - processTokenInForeignContent(token); + processTokenInForeignContent(WTFMove(token)); else - processToken(token); + processToken(WTFMove(token)); - if (m_parser.tokenizer()) { - bool inForeignContent = !m_tree.isEmpty() - && !m_tree.currentStackItem()->isInHTMLNamespace() - && !HTMLElementStack::isHTMLIntegrationPoint(m_tree.currentStackItem()) - && !HTMLElementStack::isMathMLTextIntegrationPoint(m_tree.currentStackItem()); + bool inForeignContent = !m_tree.isEmpty() + && !isInHTMLNamespace(adjustedCurrentStackItem()) + && !HTMLElementStack::isHTMLIntegrationPoint(m_tree.currentStackItem()) + && !HTMLElementStack::isMathMLTextIntegrationPoint(m_tree.currentStackItem()); - m_parser.tokenizer()->setForceNullCharacterReplacement(m_insertionMode == InsertionMode::Text || inForeignContent); - m_parser.tokenizer()->setShouldAllowCDATA(inForeignContent); - } + m_parser.tokenizer().setForceNullCharacterReplacement(m_insertionMode == InsertionMode::Text || inForeignContent); + m_parser.tokenizer().setShouldAllowCDATA(inForeignContent); + +#if !ASSERT_DISABLED + m_destructionProhibited = false; +#endif m_tree.executeQueuedTasks(); - // We might be detached now. + // The tree builder might have been destroyed as an indirect result of executing the queued tasks. } -void HTMLTreeBuilder::processToken(AtomicHTMLToken* token) +void HTMLTreeBuilder::processToken(AtomicHTMLToken&& token) { - switch (token->type()) { + switch (token.type()) { case HTMLToken::Uninitialized: ASSERT_NOT_REACHED(); break; case HTMLToken::DOCTYPE: m_shouldSkipLeadingNewline = false; - processDoctypeToken(token); + processDoctypeToken(WTFMove(token)); break; case HTMLToken::StartTag: m_shouldSkipLeadingNewline = false; - processStartTag(token); + processStartTag(WTFMove(token)); break; case HTMLToken::EndTag: m_shouldSkipLeadingNewline = false; - processEndTag(token); + processEndTag(WTFMove(token)); break; case HTMLToken::Comment: m_shouldSkipLeadingNewline = false; - processComment(token); + processComment(WTFMove(token)); return; case HTMLToken::Character: - processCharacter(token); + processCharacter(WTFMove(token)); break; case HTMLToken::EndOfFile: m_shouldSkipLeadingNewline = false; - processEndOfFile(token); + processEndOfFile(WTFMove(token)); break; } } -void HTMLTreeBuilder::processDoctypeToken(AtomicHTMLToken* token) +void HTMLTreeBuilder::processDoctypeToken(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::DOCTYPE); + ASSERT(token.type() == HTMLToken::DOCTYPE); if (m_insertionMode == InsertionMode::Initial) { - m_tree.insertDoctype(token); - setInsertionMode(InsertionMode::BeforeHTML); + m_tree.insertDoctype(WTFMove(token)); + m_insertionMode = InsertionMode::BeforeHTML; return; } if (m_insertionMode == InsertionMode::InTableText) { defaultForInTableText(); - processDoctypeToken(token); + processDoctypeToken(WTFMove(token)); return; } parseError(token); } -void HTMLTreeBuilder::processFakeStartTag(const QualifiedName& tagName, const Vector<Attribute>& attributes) +void HTMLTreeBuilder::processFakeStartTag(const QualifiedName& tagName, Vector<Attribute>&& attributes) { // FIXME: We'll need a fancier conversion than just "localName" for SVG/MathML tags. - AtomicHTMLToken fakeToken(HTMLToken::StartTag, tagName.localName(), attributes); - processStartTag(&fakeToken); + AtomicHTMLToken fakeToken(HTMLToken::StartTag, tagName.localName(), WTFMove(attributes)); + processStartTag(WTFMove(fakeToken)); } void HTMLTreeBuilder::processFakeEndTag(const AtomicString& tagName) { AtomicHTMLToken fakeToken(HTMLToken::EndTag, tagName); - processEndTag(&fakeToken); + processEndTag(WTFMove(fakeToken)); } void HTMLTreeBuilder::processFakeEndTag(const QualifiedName& tagName) @@ -462,428 +442,363 @@ void HTMLTreeBuilder::processFakeCharacters(const String& characters) void HTMLTreeBuilder::processFakePEndTagIfPInButtonScope() { - if (!m_tree.openElements()->inButtonScope(pTag.localName())) + if (!m_tree.openElements().inButtonScope(pTag.localName())) return; AtomicHTMLToken endP(HTMLToken::EndTag, pTag.localName()); - processEndTag(&endP); -} - -Vector<Attribute> HTMLTreeBuilder::attributesForIsindexInput(AtomicHTMLToken* token) -{ - Vector<Attribute> attributes = token->attributes(); - for (int i = attributes.size() - 1; i >= 0; --i) { - const QualifiedName& name = attributes.at(i).name(); - if (name.matches(nameAttr) || name.matches(actionAttr) || name.matches(promptAttr)) - attributes.remove(i); - } - - attributes.append(Attribute(nameAttr, isindexTag.localName())); - return attributes; -} - -void HTMLTreeBuilder::processIsindexStartTagForInBody(AtomicHTMLToken* token) -{ - ASSERT(token->type() == HTMLToken::StartTag); - ASSERT(token->name() == isindexTag); - parseError(token); - if (m_tree.form() && !isParsingTemplateContents()) - return; - notImplemented(); // Acknowledge self-closing flag - processFakeStartTag(formTag); - Attribute* actionAttribute = token->getAttributeItem(actionAttr); - if (actionAttribute) - m_tree.form()->setAttribute(actionAttr, actionAttribute->value()); - processFakeStartTag(hrTag); - processFakeStartTag(labelTag); - Attribute* promptAttribute = token->getAttributeItem(promptAttr); - if (promptAttribute) - processFakeCharacters(promptAttribute->value()); - else - processFakeCharacters(searchableIndexIntroduction()); - processFakeStartTag(inputTag, attributesForIsindexInput(token)); - notImplemented(); // This second set of characters may be needed by non-english locales. - processFakeEndTag(labelTag); - processFakeStartTag(hrTag); - processFakeEndTag(formTag); + processEndTag(WTFMove(endP)); } namespace { -bool isLi(const HTMLStackItem* item) +bool isLi(const HTMLStackItem& item) { - return item->hasTagName(liTag); + return item.hasTagName(liTag); } -bool isDdOrDt(const HTMLStackItem* item) +bool isDdOrDt(const HTMLStackItem& item) { - return item->hasTagName(ddTag) - || item->hasTagName(dtTag); + return item.hasTagName(ddTag) || item.hasTagName(dtTag); } } -template <bool shouldClose(const HTMLStackItem*)> -void HTMLTreeBuilder::processCloseWhenNestedTag(AtomicHTMLToken* token) +template <bool shouldClose(const HTMLStackItem&)> void HTMLTreeBuilder::processCloseWhenNestedTag(AtomicHTMLToken&& token) { m_framesetOk = false; - HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord(); - while (1) { - RefPtr<HTMLStackItem> item = nodeRecord->stackItem(); - if (shouldClose(item.get())) { - ASSERT(item->isElementNode()); - processFakeEndTag(item->localName()); + for (auto* nodeRecord = &m_tree.openElements().topRecord(); ; nodeRecord = nodeRecord->next()) { + HTMLStackItem& item = nodeRecord->stackItem(); + if (shouldClose(item)) { + ASSERT(item.isElement()); + processFakeEndTag(item.localName()); break; } - if (item->isSpecialNode() && !item->hasTagName(addressTag) && !item->hasTagName(divTag) && !item->hasTagName(pTag)) + if (isSpecialNode(item) && !item.hasTagName(addressTag) && !item.hasTagName(divTag) && !item.hasTagName(pTag)) break; - nodeRecord = nodeRecord->next(); } processFakePEndTagIfPInButtonScope(); - m_tree.insertHTMLElement(token); + m_tree.insertHTMLElement(WTFMove(token)); } -typedef HashMap<AtomicString, QualifiedName> PrefixedNameToQualifiedNameMap; - -static void mapLoweredLocalNameToName(PrefixedNameToQualifiedNameMap* map, const QualifiedName* const names[], size_t length) +template <typename TableQualifiedName> static HashMap<AtomicString, QualifiedName> createCaseMap(const TableQualifiedName* const names[], unsigned length) { - for (size_t i = 0; i < length; ++i) { + HashMap<AtomicString, QualifiedName> map; + for (unsigned i = 0; i < length; ++i) { const QualifiedName& name = *names[i]; const AtomicString& localName = name.localName(); - AtomicString loweredLocalName = localName.lower(); + AtomicString loweredLocalName = localName.convertToASCIILowercase(); if (loweredLocalName != localName) - map->add(loweredLocalName, name); + map.add(loweredLocalName, name); } + return map; } -static void adjustSVGTagNameCase(AtomicHTMLToken* token) +static void adjustSVGTagNameCase(AtomicHTMLToken& token) { - static PrefixedNameToQualifiedNameMap* caseMap = 0; - if (!caseMap) { - caseMap = new PrefixedNameToQualifiedNameMap; - mapLoweredLocalNameToName(caseMap, SVGNames::getSVGTags(), SVGNames::SVGTagsCount); - } - - const QualifiedName& casedName = caseMap->get(token->name()); + static NeverDestroyed<HashMap<AtomicString, QualifiedName>> map = createCaseMap(SVGNames::getSVGTags(), SVGNames::SVGTagsCount); + const QualifiedName& casedName = map.get().get(token.name()); if (casedName.localName().isNull()) return; - token->setName(casedName.localName()); + token.setName(casedName.localName()); } -template<const QualifiedName* const * getAttrs(), unsigned length> -static void adjustAttributes(AtomicHTMLToken* token) +static inline void adjustAttributes(HashMap<AtomicString, QualifiedName>& map, AtomicHTMLToken& token) { - static PrefixedNameToQualifiedNameMap* caseMap = 0; - if (!caseMap) { - caseMap = new PrefixedNameToQualifiedNameMap; - mapLoweredLocalNameToName(caseMap, getAttrs(), length); - } - - for (unsigned i = 0; i < token->attributes().size(); ++i) { - Attribute& tokenAttribute = token->attributes().at(i); - const QualifiedName& casedName = caseMap->get(tokenAttribute.localName()); + for (auto& attribute : token.attributes()) { + const QualifiedName& casedName = map.get(attribute.localName()); if (!casedName.localName().isNull()) - tokenAttribute.parserSetName(casedName); + attribute.parserSetName(casedName); } } -static void adjustSVGAttributes(AtomicHTMLToken* token) +template<const QualifiedName* const* attributesTable(), unsigned attributesTableLength> static void adjustAttributes(AtomicHTMLToken& token) +{ + static NeverDestroyed<HashMap<AtomicString, QualifiedName>> map = createCaseMap(attributesTable(), attributesTableLength); + adjustAttributes(map, token); +} + +static inline void adjustSVGAttributes(AtomicHTMLToken& token) { adjustAttributes<SVGNames::getSVGAttrs, SVGNames::SVGAttrsCount>(token); } -static void adjustMathMLAttributes(AtomicHTMLToken* token) +static inline void adjustMathMLAttributes(AtomicHTMLToken& token) { adjustAttributes<MathMLNames::getMathMLAttrs, MathMLNames::MathMLAttrsCount>(token); } -static void addNamesWithPrefix(PrefixedNameToQualifiedNameMap* map, const AtomicString& prefix, const QualifiedName* const names[], size_t length) +static void addNamesWithPrefix(HashMap<AtomicString, QualifiedName>& map, const AtomicString& prefix, const QualifiedName* const names[], unsigned length) { - for (size_t i = 0; i < length; ++i) { + for (unsigned i = 0; i < length; ++i) { const QualifiedName& name = *names[i]; const AtomicString& localName = name.localName(); - AtomicString prefixColonLocalName = prefix + ':' + localName; - QualifiedName nameWithPrefix(prefix, localName, name.namespaceURI()); - map->add(prefixColonLocalName, nameWithPrefix); + map.add(prefix + ':' + localName, QualifiedName(prefix, localName, name.namespaceURI())); } } -static void adjustForeignAttributes(AtomicHTMLToken* token) +static HashMap<AtomicString, QualifiedName> createForeignAttributesMap() { - static PrefixedNameToQualifiedNameMap* map = 0; - if (!map) { - map = new PrefixedNameToQualifiedNameMap; + HashMap<AtomicString, QualifiedName> map; - addNamesWithPrefix(map, xlinkAtom, XLinkNames::getXLinkAttrs(), XLinkNames::XLinkAttrsCount); + AtomicString xlinkName("xlink", AtomicString::ConstructFromLiteral); + addNamesWithPrefix(map, xlinkName, XLinkNames::getXLinkAttrs(), XLinkNames::XLinkAttrsCount); + addNamesWithPrefix(map, xmlAtom, XMLNames::getXMLAttrs(), XMLNames::XMLAttrsCount); - addNamesWithPrefix(map, xmlAtom, XMLNames::getXMLAttrs(), XMLNames::XMLAttrsCount); + map.add(WTF::xmlnsAtom, XMLNSNames::xmlnsAttr); + map.add("xmlns:xlink", QualifiedName(xmlnsAtom, xlinkName, XMLNSNames::xmlnsNamespaceURI)); - map->add(WTF::xmlnsAtom, XMLNSNames::xmlnsAttr); - map->add("xmlns:xlink", QualifiedName(xmlnsAtom, xlinkAtom, XMLNSNames::xmlnsNamespaceURI)); - } + return map; +} - for (unsigned i = 0; i < token->attributes().size(); ++i) { - Attribute& tokenAttribute = token->attributes().at(i); - const QualifiedName& name = map->get(tokenAttribute.localName()); - if (!name.localName().isNull()) - tokenAttribute.parserSetName(name); - } +static void adjustForeignAttributes(AtomicHTMLToken& token) +{ + static NeverDestroyed<HashMap<AtomicString, QualifiedName>> map = createForeignAttributesMap(); + adjustAttributes(map, token); } -void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken* token) +void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::StartTag); - if (token->name() == htmlTag) { - processHtmlStartTagForInBody(token); + ASSERT(token.type() == HTMLToken::StartTag); + if (token.name() == htmlTag) { + processHtmlStartTagForInBody(WTFMove(token)); return; } - if (token->name() == baseTag - || token->name() == basefontTag - || token->name() == bgsoundTag - || token->name() == commandTag - || token->name() == linkTag - || token->name() == metaTag - || token->name() == noframesTag - || token->name() == scriptTag - || token->name() == styleTag - || token->name() == titleTag) { - bool didProcess = processStartTagForInHead(token); + if (token.name() == baseTag + || token.name() == basefontTag + || token.name() == bgsoundTag + || token.name() == commandTag + || token.name() == linkTag + || token.name() == metaTag + || token.name() == noframesTag + || token.name() == scriptTag + || token.name() == styleTag + || token.name() == titleTag) { + bool didProcess = processStartTagForInHead(WTFMove(token)); ASSERT_UNUSED(didProcess, didProcess); return; } - if (token->name() == bodyTag) { + if (token.name() == bodyTag) { parseError(token); - bool fragmentOrTemplateCase = !m_tree.openElements()->secondElementIsHTMLBodyElement() || m_tree.openElements()->hasOnlyOneElement(); -#if ENABLE(TEMPLATE_ELEMENT) - fragmentOrTemplateCase = fragmentOrTemplateCase || m_tree.openElements()->hasTemplateInHTMLScope(); -#endif + bool fragmentOrTemplateCase = !m_tree.openElements().secondElementIsHTMLBodyElement() || m_tree.openElements().hasOnlyOneElement() + || m_tree.openElements().hasTemplateInHTMLScope(); if (fragmentOrTemplateCase) { ASSERT(isParsingFragmentOrTemplateContents()); return; } m_framesetOk = false; - m_tree.insertHTMLBodyStartTagInBody(token); + m_tree.insertHTMLBodyStartTagInBody(WTFMove(token)); return; } - if (token->name() == framesetTag) { + if (token.name() == framesetTag) { parseError(token); - if (!m_tree.openElements()->secondElementIsHTMLBodyElement() || m_tree.openElements()->hasOnlyOneElement()) { + if (!m_tree.openElements().secondElementIsHTMLBodyElement() || m_tree.openElements().hasOnlyOneElement()) { ASSERT(isParsingFragmentOrTemplateContents()); return; } if (!m_framesetOk) return; - m_tree.openElements()->bodyElement()->remove(ASSERT_NO_EXCEPTION); - m_tree.openElements()->popUntil(m_tree.openElements()->bodyElement()); - m_tree.openElements()->popHTMLBodyElement(); - ASSERT(m_tree.openElements()->top() == m_tree.openElements()->htmlElement()); - m_tree.insertHTMLElement(token); - setInsertionMode(InsertionMode::InFrameset); - return; - } - if (token->name() == addressTag - || token->name() == articleTag - || token->name() == asideTag - || token->name() == blockquoteTag - || token->name() == centerTag - || token->name() == detailsTag - || token->name() == dirTag - || token->name() == divTag - || token->name() == dlTag - || token->name() == fieldsetTag - || token->name() == figcaptionTag - || token->name() == figureTag - || token->name() == footerTag - || token->name() == headerTag - || token->name() == hgroupTag - || token->name() == mainTag - || token->name() == menuTag - || token->name() == navTag - || token->name() == olTag - || token->name() == pTag - || token->name() == sectionTag - || token->name() == summaryTag - || token->name() == ulTag) { + m_tree.openElements().bodyElement().remove(); + m_tree.openElements().popUntil(m_tree.openElements().bodyElement()); + m_tree.openElements().popHTMLBodyElement(); + // Note: in the fragment case the root is a DocumentFragment instead of a proper html element which is a quirk / optimization in WebKit. + ASSERT(!isParsingFragment() || is<DocumentFragment>(m_tree.openElements().topNode())); + ASSERT(isParsingFragment() || &m_tree.openElements().top() == &m_tree.openElements().htmlElement()); + m_tree.insertHTMLElement(WTFMove(token)); + m_insertionMode = InsertionMode::InFrameset; + return; + } + if (token.name() == addressTag + || token.name() == articleTag + || token.name() == asideTag + || token.name() == blockquoteTag + || token.name() == centerTag + || token.name() == detailsTag + || token.name() == dirTag + || token.name() == divTag + || token.name() == dlTag + || token.name() == fieldsetTag + || token.name() == figcaptionTag + || token.name() == figureTag + || token.name() == footerTag + || token.name() == headerTag + || token.name() == hgroupTag + || token.name() == mainTag + || token.name() == menuTag + || token.name() == navTag + || token.name() == olTag + || token.name() == pTag + || token.name() == sectionTag + || token.name() == summaryTag + || token.name() == ulTag) { processFakePEndTagIfPInButtonScope(); - m_tree.insertHTMLElement(token); + m_tree.insertHTMLElement(WTFMove(token)); return; } - if (isNumberedHeaderTag(token->name())) { + if (isNumberedHeaderTag(token.name())) { processFakePEndTagIfPInButtonScope(); - if (m_tree.currentStackItem()->isNumberedHeaderElement()) { + if (isNumberedHeaderElement(m_tree.currentStackItem())) { parseError(token); - m_tree.openElements()->pop(); + m_tree.openElements().pop(); } - m_tree.insertHTMLElement(token); + m_tree.insertHTMLElement(WTFMove(token)); return; } - if (token->name() == preTag || token->name() == listingTag) { + if (token.name() == preTag || token.name() == listingTag) { processFakePEndTagIfPInButtonScope(); - m_tree.insertHTMLElement(token); + m_tree.insertHTMLElement(WTFMove(token)); m_shouldSkipLeadingNewline = true; m_framesetOk = false; return; } - if (token->name() == formTag) { + if (token.name() == formTag) { if (m_tree.form() && !isParsingTemplateContents()) { parseError(token); return; } processFakePEndTagIfPInButtonScope(); - m_tree.insertHTMLFormElement(token); + m_tree.insertHTMLFormElement(WTFMove(token)); return; } - if (token->name() == liTag) { - processCloseWhenNestedTag<isLi>(token); + if (token.name() == liTag) { + processCloseWhenNestedTag<isLi>(WTFMove(token)); return; } - if (token->name() == ddTag || token->name() == dtTag) { - processCloseWhenNestedTag<isDdOrDt>(token); + if (token.name() == ddTag || token.name() == dtTag) { + processCloseWhenNestedTag<isDdOrDt>(WTFMove(token)); return; } - if (token->name() == plaintextTag) { + if (token.name() == plaintextTag) { processFakePEndTagIfPInButtonScope(); - m_tree.insertHTMLElement(token); - if (m_parser.tokenizer()) - m_parser.tokenizer()->setState(HTMLTokenizer::PLAINTEXTState); + m_tree.insertHTMLElement(WTFMove(token)); + m_parser.tokenizer().setPLAINTEXTState(); return; } - if (token->name() == buttonTag) { - if (m_tree.openElements()->inScope(buttonTag)) { + if (token.name() == buttonTag) { + if (m_tree.openElements().inScope(buttonTag)) { parseError(token); processFakeEndTag(buttonTag); - processStartTag(token); // FIXME: Could we just fall through here? + processStartTag(WTFMove(token)); // FIXME: Could we just fall through here? return; } m_tree.reconstructTheActiveFormattingElements(); - m_tree.insertHTMLElement(token); + m_tree.insertHTMLElement(WTFMove(token)); m_framesetOk = false; return; } - if (token->name() == aTag) { - Element* activeATag = m_tree.activeFormattingElements()->closestElementInScopeWithName(aTag.localName()); + if (token.name() == aTag) { + Element* activeATag = m_tree.activeFormattingElements().closestElementInScopeWithName(aTag.localName()); if (activeATag) { parseError(token); processFakeEndTag(aTag); - m_tree.activeFormattingElements()->remove(activeATag); - if (m_tree.openElements()->contains(activeATag)) - m_tree.openElements()->remove(activeATag); + m_tree.activeFormattingElements().remove(*activeATag); + if (m_tree.openElements().contains(*activeATag)) + m_tree.openElements().remove(*activeATag); } m_tree.reconstructTheActiveFormattingElements(); - m_tree.insertFormattingElement(token); + m_tree.insertFormattingElement(WTFMove(token)); return; } - if (isNonAnchorNonNobrFormattingTag(token->name())) { + if (isNonAnchorNonNobrFormattingTag(token.name())) { m_tree.reconstructTheActiveFormattingElements(); - m_tree.insertFormattingElement(token); + m_tree.insertFormattingElement(WTFMove(token)); return; } - if (token->name() == nobrTag) { + if (token.name() == nobrTag) { m_tree.reconstructTheActiveFormattingElements(); - if (m_tree.openElements()->inScope(nobrTag)) { + if (m_tree.openElements().inScope(nobrTag)) { parseError(token); processFakeEndTag(nobrTag); m_tree.reconstructTheActiveFormattingElements(); } - m_tree.insertFormattingElement(token); + m_tree.insertFormattingElement(WTFMove(token)); return; } - if (token->name() == appletTag - || token->name() == embedTag - || token->name() == objectTag) { + if (token.name() == appletTag || token.name() == embedTag || token.name() == objectTag) { if (!pluginContentIsAllowed(m_tree.parserContentPolicy())) return; } - if (token->name() == appletTag - || token->name() == marqueeTag - || token->name() == objectTag) { + if (token.name() == appletTag || token.name() == marqueeTag || token.name() == objectTag) { m_tree.reconstructTheActiveFormattingElements(); - m_tree.insertHTMLElement(token); - m_tree.activeFormattingElements()->appendMarker(); + m_tree.insertHTMLElement(WTFMove(token)); + m_tree.activeFormattingElements().appendMarker(); m_framesetOk = false; return; } - if (token->name() == tableTag) { - if (!m_tree.inQuirksMode() && m_tree.openElements()->inButtonScope(pTag)) + if (token.name() == tableTag) { + if (!m_tree.inQuirksMode() && m_tree.openElements().inButtonScope(pTag)) processFakeEndTag(pTag); - m_tree.insertHTMLElement(token); + m_tree.insertHTMLElement(WTFMove(token)); m_framesetOk = false; - setInsertionMode(InsertionMode::InTable); + m_insertionMode = InsertionMode::InTable; return; } - if (token->name() == imageTag) { + if (token.name() == imageTag) { parseError(token); // Apparently we're not supposed to ask. - token->setName(imgTag.localName()); + token.setName(imgTag.localName()); // Note the fall through to the imgTag handling below! } - if (token->name() == areaTag - || token->name() == brTag - || token->name() == embedTag - || token->name() == imgTag - || token->name() == keygenTag - || token->name() == wbrTag) { + if (token.name() == areaTag + || token.name() == brTag + || token.name() == embedTag + || token.name() == imgTag + || token.name() == keygenTag + || token.name() == wbrTag) { m_tree.reconstructTheActiveFormattingElements(); - m_tree.insertSelfClosingHTMLElement(token); + m_tree.insertSelfClosingHTMLElement(WTFMove(token)); m_framesetOk = false; return; } - if (token->name() == inputTag) { - Attribute* typeAttribute = token->getAttributeItem(typeAttr); + if (token.name() == inputTag) { m_tree.reconstructTheActiveFormattingElements(); - m_tree.insertSelfClosingHTMLElement(token); - if (!typeAttribute || !equalIgnoringCase(typeAttribute->value(), "hidden")) + auto* typeAttribute = findAttribute(token.attributes(), typeAttr); + bool shouldClearFramesetOK = !typeAttribute || !equalLettersIgnoringASCIICase(typeAttribute->value(), "hidden"); + m_tree.insertSelfClosingHTMLElement(WTFMove(token)); + if (shouldClearFramesetOK) m_framesetOk = false; return; } - if (token->name() == paramTag - || token->name() == sourceTag - || token->name() == trackTag) { - m_tree.insertSelfClosingHTMLElement(token); + if (token.name() == paramTag || token.name() == sourceTag || token.name() == trackTag) { + m_tree.insertSelfClosingHTMLElement(WTFMove(token)); return; } - if (token->name() == hrTag) { + if (token.name() == hrTag) { processFakePEndTagIfPInButtonScope(); - m_tree.insertSelfClosingHTMLElement(token); + m_tree.insertSelfClosingHTMLElement(WTFMove(token)); m_framesetOk = false; return; } - if (token->name() == isindexTag) { - processIsindexStartTagForInBody(token); - return; - } - if (token->name() == textareaTag) { - m_tree.insertHTMLElement(token); + if (token.name() == textareaTag) { + m_tree.insertHTMLElement(WTFMove(token)); m_shouldSkipLeadingNewline = true; - if (m_parser.tokenizer()) - m_parser.tokenizer()->setState(HTMLTokenizer::RCDATAState); + m_parser.tokenizer().setRCDATAState(); m_originalInsertionMode = m_insertionMode; m_framesetOk = false; - setInsertionMode(InsertionMode::Text); + m_insertionMode = InsertionMode::Text; return; } - if (token->name() == xmpTag) { + if (token.name() == xmpTag) { processFakePEndTagIfPInButtonScope(); m_tree.reconstructTheActiveFormattingElements(); m_framesetOk = false; - processGenericRawTextStartTag(token); + processGenericRawTextStartTag(WTFMove(token)); return; } - if (token->name() == iframeTag) { + if (token.name() == iframeTag) { m_framesetOk = false; - processGenericRawTextStartTag(token); + processGenericRawTextStartTag(WTFMove(token)); return; } - if (token->name() == noembedTag && m_options.pluginsEnabled) { - processGenericRawTextStartTag(token); + if (token.name() == noembedTag && m_options.pluginsEnabled) { + processGenericRawTextStartTag(WTFMove(token)); return; } - if (token->name() == noscriptTag && m_options.scriptEnabled) { - processGenericRawTextStartTag(token); + if (token.name() == noscriptTag && m_options.scriptEnabled) { + processGenericRawTextStartTag(WTFMove(token)); return; } - if (token->name() == selectTag) { + if (token.name() == selectTag) { m_tree.reconstructTheActiveFormattingElements(); - m_tree.insertHTMLElement(token); + m_tree.insertHTMLElement(WTFMove(token)); m_framesetOk = false; if (m_insertionMode == InsertionMode::InTable || m_insertionMode == InsertionMode::InCaption @@ -891,576 +806,556 @@ void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken* token) || m_insertionMode == InsertionMode::InTableBody || m_insertionMode == InsertionMode::InRow || m_insertionMode == InsertionMode::InCell) - setInsertionMode(InsertionMode::InSelectInTable); + m_insertionMode = InsertionMode::InSelectInTable; else - setInsertionMode(InsertionMode::InSelect); + m_insertionMode = InsertionMode::InSelect; return; } - if (token->name() == optgroupTag || token->name() == optionTag) { - if (isHTMLOptionElement(m_tree.currentStackItem()->node())) { + if (token.name() == optgroupTag || token.name() == optionTag) { + if (is<HTMLOptionElement>(m_tree.currentStackItem().node())) { AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName()); - processEndTag(&endOption); + processEndTag(WTFMove(endOption)); } m_tree.reconstructTheActiveFormattingElements(); - m_tree.insertHTMLElement(token); + m_tree.insertHTMLElement(WTFMove(token)); return; } - if (token->name() == rpTag || token->name() == rtTag) { - if (m_tree.openElements()->inScope(rubyTag.localName())) { + if (token.name() == rbTag || token.name() == rtcTag) { + if (m_tree.openElements().inScope(rubyTag.localName())) { m_tree.generateImpliedEndTags(); - if (!m_tree.currentStackItem()->hasTagName(rubyTag)) + if (!m_tree.currentStackItem().hasTagName(rubyTag)) parseError(token); } - m_tree.insertHTMLElement(token); + m_tree.insertHTMLElement(WTFMove(token)); return; } - if (token->name() == MathMLNames::mathTag.localName()) { + if (token.name() == rtTag || token.name() == rpTag) { + if (m_tree.openElements().inScope(rubyTag.localName())) { + m_tree.generateImpliedEndTagsWithExclusion(rtcTag.localName()); + if (!m_tree.currentStackItem().hasTagName(rubyTag) && !m_tree.currentStackItem().hasTagName(rtcTag)) + parseError(token); + } + m_tree.insertHTMLElement(WTFMove(token)); + return; + } + if (token.name() == MathMLNames::mathTag.localName()) { m_tree.reconstructTheActiveFormattingElements(); adjustMathMLAttributes(token); adjustForeignAttributes(token); - m_tree.insertForeignElement(token, MathMLNames::mathmlNamespaceURI); + m_tree.insertForeignElement(WTFMove(token), MathMLNames::mathmlNamespaceURI); return; } - if (token->name() == SVGNames::svgTag.localName()) { + if (token.name() == SVGNames::svgTag.localName()) { m_tree.reconstructTheActiveFormattingElements(); adjustSVGAttributes(token); adjustForeignAttributes(token); - m_tree.insertForeignElement(token, SVGNames::svgNamespaceURI); + m_tree.insertForeignElement(WTFMove(token), SVGNames::svgNamespaceURI); return; } - if (isCaptionColOrColgroupTag(token->name()) - || token->name() == frameTag - || token->name() == headTag - || isTableBodyContextTag(token->name()) - || isTableCellContextTag(token->name()) - || token->name() == trTag) { + if (isCaptionColOrColgroupTag(token.name()) + || token.name() == frameTag + || token.name() == headTag + || isTableBodyContextTag(token.name()) + || isTableCellContextTag(token.name()) + || token.name() == trTag) { parseError(token); return; } -#if ENABLE(TEMPLATE_ELEMENT) - if (token->name() == templateTag) { - processTemplateStartTag(token); + if (token.name() == templateTag) { + m_framesetOk = false; + processTemplateStartTag(WTFMove(token)); return; } -#endif m_tree.reconstructTheActiveFormattingElements(); - m_tree.insertHTMLElement(token); + insertGenericHTMLElement(WTFMove(token)); } -#if ENABLE(TEMPLATE_ELEMENT) -void HTMLTreeBuilder::processTemplateStartTag(AtomicHTMLToken* token) +inline void HTMLTreeBuilder::insertGenericHTMLElement(AtomicHTMLToken&& token) { - m_tree.activeFormattingElements()->appendMarker(); - m_tree.insertHTMLElement(token); + m_customElementToConstruct = m_tree.insertHTMLElementOrFindCustomElementInterface(WTFMove(token)); +} + +void HTMLTreeBuilder::didCreateCustomOrCallbackElement(Ref<Element>&& element, CustomElementConstructionData& data) +{ + m_tree.insertCustomElement(WTFMove(element), data.name, WTFMove(data.attributes)); +} + +void HTMLTreeBuilder::processTemplateStartTag(AtomicHTMLToken&& token) +{ + m_tree.activeFormattingElements().appendMarker(); + m_tree.insertHTMLElement(WTFMove(token)); m_templateInsertionModes.append(InsertionMode::TemplateContents); - setInsertionMode(InsertionMode::TemplateContents); + m_insertionMode = InsertionMode::TemplateContents; } -bool HTMLTreeBuilder::processTemplateEndTag(AtomicHTMLToken* token) +bool HTMLTreeBuilder::processTemplateEndTag(AtomicHTMLToken&& token) { - ASSERT(token->name() == templateTag.localName()); - if (!m_tree.openElements()->hasTemplateInHTMLScope()) { - ASSERT(m_templateInsertionModes.isEmpty() || (m_templateInsertionModes.size() == 1 && m_fragmentContext.contextElement()->hasTagName(templateTag))); + ASSERT(token.name() == templateTag.localName()); + if (!m_tree.openElements().hasTemplateInHTMLScope()) { + ASSERT(m_templateInsertionModes.isEmpty() || (m_templateInsertionModes.size() == 1 && m_fragmentContext.contextElement().hasTagName(templateTag))); parseError(token); return false; } m_tree.generateImpliedEndTags(); - if (!m_tree.currentStackItem()->hasTagName(templateTag)) + if (!m_tree.currentStackItem().hasTagName(templateTag)) parseError(token); - m_tree.openElements()->popUntilPopped(templateTag); - m_tree.activeFormattingElements()->clearToLastMarker(); + m_tree.openElements().popUntilPopped(templateTag); + m_tree.activeFormattingElements().clearToLastMarker(); m_templateInsertionModes.removeLast(); resetInsertionModeAppropriately(); return true; } -bool HTMLTreeBuilder::processEndOfFileForInTemplateContents(AtomicHTMLToken* token) +bool HTMLTreeBuilder::processEndOfFileForInTemplateContents(AtomicHTMLToken&& token) { AtomicHTMLToken endTemplate(HTMLToken::EndTag, templateTag.localName()); - if (!processTemplateEndTag(&endTemplate)) + if (!processTemplateEndTag(WTFMove(endTemplate))) return false; - processEndOfFile(token); + processEndOfFile(WTFMove(token)); return true; } -#endif bool HTMLTreeBuilder::processColgroupEndTagForInColumnGroup() { - bool ignoreFakeEndTag = m_tree.currentIsRootNode(); -#if ENABLE(TEMPLATE_ELEMENT) - ignoreFakeEndTag = ignoreFakeEndTag || m_tree.currentNode()->hasTagName(templateTag); -#endif + bool ignoreFakeEndTag = m_tree.currentIsRootNode() || m_tree.currentNode().hasTagName(templateTag); if (ignoreFakeEndTag) { ASSERT(isParsingFragmentOrTemplateContents()); // FIXME: parse error return false; } - m_tree.openElements()->pop(); - setInsertionMode(InsertionMode::InTable); + m_tree.openElements().pop(); + m_insertionMode = InsertionMode::InTable; return true; } // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#close-the-cell void HTMLTreeBuilder::closeTheCell() { - ASSERT(insertionMode() == InsertionMode::InCell); - if (m_tree.openElements()->inTableScope(tdTag)) { - ASSERT(!m_tree.openElements()->inTableScope(thTag)); + ASSERT(m_insertionMode == InsertionMode::InCell); + if (m_tree.openElements().inTableScope(tdTag)) { + ASSERT(!m_tree.openElements().inTableScope(thTag)); processFakeEndTag(tdTag); return; } - ASSERT(m_tree.openElements()->inTableScope(thTag)); + ASSERT(m_tree.openElements().inTableScope(thTag)); processFakeEndTag(thTag); - ASSERT(insertionMode() == InsertionMode::InRow); + ASSERT(m_insertionMode == InsertionMode::InRow); } -void HTMLTreeBuilder::processStartTagForInTable(AtomicHTMLToken* token) +void HTMLTreeBuilder::processStartTagForInTable(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::StartTag); - if (token->name() == captionTag) { - m_tree.openElements()->popUntilTableScopeMarker(); - m_tree.activeFormattingElements()->appendMarker(); - m_tree.insertHTMLElement(token); - setInsertionMode(InsertionMode::InCaption); + ASSERT(token.type() == HTMLToken::StartTag); + if (token.name() == captionTag) { + m_tree.openElements().popUntilTableScopeMarker(); + m_tree.activeFormattingElements().appendMarker(); + m_tree.insertHTMLElement(WTFMove(token)); + m_insertionMode = InsertionMode::InCaption; return; } - if (token->name() == colgroupTag) { - m_tree.openElements()->popUntilTableScopeMarker(); - m_tree.insertHTMLElement(token); - setInsertionMode(InsertionMode::InColumnGroup); + if (token.name() == colgroupTag) { + m_tree.openElements().popUntilTableScopeMarker(); + m_tree.insertHTMLElement(WTFMove(token)); + m_insertionMode = InsertionMode::InColumnGroup; return; } - if (token->name() == colTag) { + if (token.name() == colTag) { processFakeStartTag(colgroupTag); - ASSERT(insertionMode() == InsertionMode::InColumnGroup); - processStartTag(token); + ASSERT(m_insertionMode == InsertionMode::InColumnGroup); + processStartTag(WTFMove(token)); return; } - if (isTableBodyContextTag(token->name())) { - m_tree.openElements()->popUntilTableScopeMarker(); - m_tree.insertHTMLElement(token); - setInsertionMode(InsertionMode::InTableBody); + if (isTableBodyContextTag(token.name())) { + m_tree.openElements().popUntilTableScopeMarker(); + m_tree.insertHTMLElement(WTFMove(token)); + m_insertionMode = InsertionMode::InTableBody; return; } - if (isTableCellContextTag(token->name()) - || token->name() == trTag) { + if (isTableCellContextTag(token.name()) || token.name() == trTag) { processFakeStartTag(tbodyTag); - ASSERT(insertionMode() == InsertionMode::InTableBody); - processStartTag(token); + ASSERT(m_insertionMode == InsertionMode::InTableBody); + processStartTag(WTFMove(token)); return; } - if (token->name() == tableTag) { + if (token.name() == tableTag) { parseError(token); if (!processTableEndTagForInTable()) { ASSERT(isParsingFragmentOrTemplateContents()); return; } - processStartTag(token); + processStartTag(WTFMove(token)); return; } - if (token->name() == styleTag || token->name() == scriptTag) { - processStartTagForInHead(token); + if (token.name() == styleTag || token.name() == scriptTag) { + processStartTagForInHead(WTFMove(token)); return; } - if (token->name() == inputTag) { - Attribute* typeAttribute = token->getAttributeItem(typeAttr); - if (typeAttribute && equalIgnoringCase(typeAttribute->value(), "hidden")) { + if (token.name() == inputTag) { + auto* typeAttribute = findAttribute(token.attributes(), typeAttr); + if (typeAttribute && equalLettersIgnoringASCIICase(typeAttribute->value(), "hidden")) { parseError(token); - m_tree.insertSelfClosingHTMLElement(token); + m_tree.insertSelfClosingHTMLElement(WTFMove(token)); return; } // Fall through to "anything else" case. } - if (token->name() == formTag) { + if (token.name() == formTag) { parseError(token); if (m_tree.form() && !isParsingTemplateContents()) return; - m_tree.insertHTMLFormElement(token, true); - m_tree.openElements()->pop(); + m_tree.insertHTMLFormElement(WTFMove(token), true); + m_tree.openElements().pop(); return; } -#if ENABLE(TEMPLATE_ELEMENT) - if (token->name() == templateTag) { - processTemplateStartTag(token); + if (token.name() == templateTag) { + processTemplateStartTag(WTFMove(token)); return; } -#endif parseError(token); HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree); - processStartTagForInBody(token); + processStartTagForInBody(WTFMove(token)); } -void HTMLTreeBuilder::processStartTag(AtomicHTMLToken* token) +void HTMLTreeBuilder::processStartTag(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::StartTag); - switch (insertionMode()) { + ASSERT(token.type() == HTMLToken::StartTag); + switch (m_insertionMode) { case InsertionMode::Initial: - ASSERT(insertionMode() == InsertionMode::Initial); defaultForInitial(); + ASSERT(m_insertionMode == InsertionMode::BeforeHTML); FALLTHROUGH; case InsertionMode::BeforeHTML: - ASSERT(insertionMode() == InsertionMode::BeforeHTML); - if (token->name() == htmlTag) { - m_tree.insertHTMLHtmlStartTagBeforeHTML(token); - setInsertionMode(InsertionMode::BeforeHead); + if (token.name() == htmlTag) { + m_tree.insertHTMLHtmlStartTagBeforeHTML(WTFMove(token)); + m_insertionMode = InsertionMode::BeforeHead; return; } defaultForBeforeHTML(); + ASSERT(m_insertionMode == InsertionMode::BeforeHead); FALLTHROUGH; case InsertionMode::BeforeHead: - ASSERT(insertionMode() == InsertionMode::BeforeHead); - if (token->name() == htmlTag) { - processHtmlStartTagForInBody(token); + if (token.name() == htmlTag) { + processHtmlStartTagForInBody(WTFMove(token)); return; } - if (token->name() == headTag) { - m_tree.insertHTMLHeadElement(token); - setInsertionMode(InsertionMode::InHead); + if (token.name() == headTag) { + m_tree.insertHTMLHeadElement(WTFMove(token)); + m_insertionMode = InsertionMode::InHead; return; } defaultForBeforeHead(); + ASSERT(m_insertionMode == InsertionMode::InHead); FALLTHROUGH; case InsertionMode::InHead: - ASSERT(insertionMode() == InsertionMode::InHead); - if (processStartTagForInHead(token)) + if (processStartTagForInHead(WTFMove(token))) return; defaultForInHead(); + ASSERT(m_insertionMode == InsertionMode::AfterHead); FALLTHROUGH; case InsertionMode::AfterHead: - ASSERT(insertionMode() == InsertionMode::AfterHead); - if (token->name() == htmlTag) { - processHtmlStartTagForInBody(token); + if (token.name() == htmlTag) { + processHtmlStartTagForInBody(WTFMove(token)); return; } - if (token->name() == bodyTag) { + if (token.name() == bodyTag) { m_framesetOk = false; - m_tree.insertHTMLBodyElement(token); - setInsertionMode(InsertionMode::InBody); + m_tree.insertHTMLBodyElement(WTFMove(token)); + m_insertionMode = InsertionMode::InBody; return; } - if (token->name() == framesetTag) { - m_tree.insertHTMLElement(token); - setInsertionMode(InsertionMode::InFrameset); + if (token.name() == framesetTag) { + m_tree.insertHTMLElement(WTFMove(token)); + m_insertionMode = InsertionMode::InFrameset; return; } - if (token->name() == baseTag - || token->name() == basefontTag - || token->name() == bgsoundTag - || token->name() == linkTag - || token->name() == metaTag - || token->name() == noframesTag - || token->name() == scriptTag - || token->name() == styleTag -#if ENABLE(TEMPLATE_ELEMENT) - || token->name() == templateTag -#endif - || token->name() == titleTag) { + if (token.name() == baseTag + || token.name() == basefontTag + || token.name() == bgsoundTag + || token.name() == linkTag + || token.name() == metaTag + || token.name() == noframesTag + || token.name() == scriptTag + || token.name() == styleTag + || token.name() == templateTag + || token.name() == titleTag) { parseError(token); - ASSERT(m_tree.head()); - m_tree.openElements()->pushHTMLHeadElement(m_tree.headStackItem()); - processStartTagForInHead(token); - m_tree.openElements()->removeHTMLHeadElement(m_tree.head()); + ASSERT(m_tree.headStackItem()); + m_tree.openElements().pushHTMLHeadElement(*m_tree.headStackItem()); + processStartTagForInHead(WTFMove(token)); + m_tree.openElements().removeHTMLHeadElement(m_tree.head()); return; } - if (token->name() == headTag) { + if (token.name() == headTag) { parseError(token); return; } defaultForAfterHead(); + ASSERT(m_insertionMode == InsertionMode::InBody); FALLTHROUGH; case InsertionMode::InBody: - ASSERT(insertionMode() == InsertionMode::InBody); - processStartTagForInBody(token); + processStartTagForInBody(WTFMove(token)); break; case InsertionMode::InTable: - ASSERT(insertionMode() == InsertionMode::InTable); - processStartTagForInTable(token); + processStartTagForInTable(WTFMove(token)); break; case InsertionMode::InCaption: - ASSERT(insertionMode() == InsertionMode::InCaption); - if (isCaptionColOrColgroupTag(token->name()) - || isTableBodyContextTag(token->name()) - || isTableCellContextTag(token->name()) - || token->name() == trTag) { + if (isCaptionColOrColgroupTag(token.name()) + || isTableBodyContextTag(token.name()) + || isTableCellContextTag(token.name()) + || token.name() == trTag) { parseError(token); if (!processCaptionEndTagForInCaption()) { ASSERT(isParsingFragment()); return; } - processStartTag(token); + processStartTag(WTFMove(token)); return; } - processStartTagForInBody(token); + processStartTagForInBody(WTFMove(token)); break; case InsertionMode::InColumnGroup: - ASSERT(insertionMode() == InsertionMode::InColumnGroup); - if (token->name() == htmlTag) { - processHtmlStartTagForInBody(token); + if (token.name() == htmlTag) { + processHtmlStartTagForInBody(WTFMove(token)); return; } - if (token->name() == colTag) { - m_tree.insertSelfClosingHTMLElement(token); + if (token.name() == colTag) { + m_tree.insertSelfClosingHTMLElement(WTFMove(token)); return; } -#if ENABLE(TEMPLATE_ELEMENT) - if (token->name() == templateTag) { - processTemplateStartTag(token); + if (token.name() == templateTag) { + processTemplateStartTag(WTFMove(token)); return; } -#endif if (!processColgroupEndTagForInColumnGroup()) { ASSERT(isParsingFragmentOrTemplateContents()); return; } - processStartTag(token); + processStartTag(WTFMove(token)); break; case InsertionMode::InTableBody: - ASSERT(insertionMode() == InsertionMode::InTableBody); - if (token->name() == trTag) { - m_tree.openElements()->popUntilTableBodyScopeMarker(); // How is there ever anything to pop? - m_tree.insertHTMLElement(token); - setInsertionMode(InsertionMode::InRow); + if (token.name() == trTag) { + m_tree.openElements().popUntilTableBodyScopeMarker(); // How is there ever anything to pop? + m_tree.insertHTMLElement(WTFMove(token)); + m_insertionMode = InsertionMode::InRow; return; } - if (isTableCellContextTag(token->name())) { + if (isTableCellContextTag(token.name())) { parseError(token); processFakeStartTag(trTag); - ASSERT(insertionMode() == InsertionMode::InRow); - processStartTag(token); + ASSERT(m_insertionMode == InsertionMode::InRow); + processStartTag(WTFMove(token)); return; } - if (isCaptionColOrColgroupTag(token->name()) || isTableBodyContextTag(token->name())) { + if (isCaptionColOrColgroupTag(token.name()) || isTableBodyContextTag(token.name())) { // FIXME: This is slow. - if (!m_tree.openElements()->inTableScope(tbodyTag) && !m_tree.openElements()->inTableScope(theadTag) && !m_tree.openElements()->inTableScope(tfootTag)) { + if (!m_tree.openElements().inTableScope(tbodyTag) && !m_tree.openElements().inTableScope(theadTag) && !m_tree.openElements().inTableScope(tfootTag)) { ASSERT(isParsingFragmentOrTemplateContents()); parseError(token); return; } - m_tree.openElements()->popUntilTableBodyScopeMarker(); - ASSERT(isTableBodyContextTag(m_tree.currentStackItem()->localName())); - processFakeEndTag(m_tree.currentStackItem()->localName()); - processStartTag(token); + m_tree.openElements().popUntilTableBodyScopeMarker(); + ASSERT(isTableBodyContextTag(m_tree.currentStackItem().localName())); + processFakeEndTag(m_tree.currentStackItem().localName()); + processStartTag(WTFMove(token)); return; } - processStartTagForInTable(token); + processStartTagForInTable(WTFMove(token)); break; case InsertionMode::InRow: - ASSERT(insertionMode() == InsertionMode::InRow); - if (isTableCellContextTag(token->name())) { - m_tree.openElements()->popUntilTableRowScopeMarker(); - m_tree.insertHTMLElement(token); - setInsertionMode(InsertionMode::InCell); - m_tree.activeFormattingElements()->appendMarker(); + if (isTableCellContextTag(token.name())) { + m_tree.openElements().popUntilTableRowScopeMarker(); + m_tree.insertHTMLElement(WTFMove(token)); + m_insertionMode = InsertionMode::InCell; + m_tree.activeFormattingElements().appendMarker(); return; } - if (token->name() == trTag - || isCaptionColOrColgroupTag(token->name()) - || isTableBodyContextTag(token->name())) { + if (token.name() == trTag + || isCaptionColOrColgroupTag(token.name()) + || isTableBodyContextTag(token.name())) { if (!processTrEndTagForInRow()) { ASSERT(isParsingFragmentOrTemplateContents()); return; } - ASSERT(insertionMode() == InsertionMode::InTableBody); - processStartTag(token); + ASSERT(m_insertionMode == InsertionMode::InTableBody); + processStartTag(WTFMove(token)); return; } - processStartTagForInTable(token); + processStartTagForInTable(WTFMove(token)); break; case InsertionMode::InCell: - ASSERT(insertionMode() == InsertionMode::InCell); - if (isCaptionColOrColgroupTag(token->name()) - || isTableCellContextTag(token->name()) - || token->name() == trTag - || isTableBodyContextTag(token->name())) { + if (isCaptionColOrColgroupTag(token.name()) + || isTableCellContextTag(token.name()) + || token.name() == trTag + || isTableBodyContextTag(token.name())) { // FIXME: This could be more efficient. - if (!m_tree.openElements()->inTableScope(tdTag) && !m_tree.openElements()->inTableScope(thTag)) { + if (!m_tree.openElements().inTableScope(tdTag) && !m_tree.openElements().inTableScope(thTag)) { ASSERT(isParsingFragment()); parseError(token); return; } closeTheCell(); - processStartTag(token); + processStartTag(WTFMove(token)); return; } - processStartTagForInBody(token); + processStartTagForInBody(WTFMove(token)); break; case InsertionMode::AfterBody: case InsertionMode::AfterAfterBody: - ASSERT(insertionMode() == InsertionMode::AfterBody || insertionMode() == InsertionMode::AfterAfterBody); - if (token->name() == htmlTag) { - processHtmlStartTagForInBody(token); + if (token.name() == htmlTag) { + processHtmlStartTagForInBody(WTFMove(token)); return; } - setInsertionMode(InsertionMode::InBody); - processStartTag(token); + m_insertionMode = InsertionMode::InBody; + processStartTag(WTFMove(token)); break; case InsertionMode::InHeadNoscript: - ASSERT(insertionMode() == InsertionMode::InHeadNoscript); - if (token->name() == htmlTag) { - processHtmlStartTagForInBody(token); - return; - } - if (token->name() == basefontTag - || token->name() == bgsoundTag - || token->name() == linkTag - || token->name() == metaTag - || token->name() == noframesTag - || token->name() == styleTag) { - bool didProcess = processStartTagForInHead(token); + if (token.name() == htmlTag) { + processHtmlStartTagForInBody(WTFMove(token)); + return; + } + if (token.name() == basefontTag + || token.name() == bgsoundTag + || token.name() == linkTag + || token.name() == metaTag + || token.name() == noframesTag + || token.name() == styleTag) { + bool didProcess = processStartTagForInHead(WTFMove(token)); ASSERT_UNUSED(didProcess, didProcess); return; } - if (token->name() == htmlTag || token->name() == noscriptTag) { + if (token.name() == htmlTag || token.name() == noscriptTag) { parseError(token); return; } defaultForInHeadNoscript(); - processToken(token); + processToken(WTFMove(token)); break; case InsertionMode::InFrameset: - ASSERT(insertionMode() == InsertionMode::InFrameset); - if (token->name() == htmlTag) { - processHtmlStartTagForInBody(token); - return; - } - if (token->name() == framesetTag) { - m_tree.insertHTMLElement(token); + if (token.name() == htmlTag) { + processHtmlStartTagForInBody(WTFMove(token)); return; } - if (token->name() == frameTag) { - m_tree.insertSelfClosingHTMLElement(token); + if (token.name() == framesetTag) { + m_tree.insertHTMLElement(WTFMove(token)); return; } - if (token->name() == noframesTag) { - processStartTagForInHead(token); + if (token.name() == frameTag) { + m_tree.insertSelfClosingHTMLElement(WTFMove(token)); return; } -#if ENABLE(TEMPLATE_ELEMENT) - if (token->name() == templateTag) { - processTemplateStartTag(token); + if (token.name() == noframesTag) { + processStartTagForInHead(WTFMove(token)); return; } -#endif parseError(token); break; case InsertionMode::AfterFrameset: case InsertionMode::AfterAfterFrameset: - ASSERT(insertionMode() == InsertionMode::AfterFrameset || insertionMode() == InsertionMode::AfterAfterFrameset); - if (token->name() == htmlTag) { - processHtmlStartTagForInBody(token); + if (token.name() == htmlTag) { + processHtmlStartTagForInBody(WTFMove(token)); return; } - if (token->name() == noframesTag) { - processStartTagForInHead(token); + if (token.name() == noframesTag) { + processStartTagForInHead(WTFMove(token)); return; } parseError(token); break; case InsertionMode::InSelectInTable: - ASSERT(insertionMode() == InsertionMode::InSelectInTable); - if (token->name() == captionTag - || token->name() == tableTag - || isTableBodyContextTag(token->name()) - || token->name() == trTag - || isTableCellContextTag(token->name())) { + if (token.name() == captionTag + || token.name() == tableTag + || isTableBodyContextTag(token.name()) + || token.name() == trTag + || isTableCellContextTag(token.name())) { parseError(token); AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName()); - processEndTag(&endSelect); - processStartTag(token); + processEndTag(WTFMove(endSelect)); + processStartTag(WTFMove(token)); return; } FALLTHROUGH; case InsertionMode::InSelect: - ASSERT(insertionMode() == InsertionMode::InSelect || insertionMode() == InsertionMode::InSelectInTable); - if (token->name() == htmlTag) { - processHtmlStartTagForInBody(token); + if (token.name() == htmlTag) { + processHtmlStartTagForInBody(WTFMove(token)); return; } - if (token->name() == optionTag) { - if (isHTMLOptionElement(m_tree.currentStackItem()->node())) { + if (token.name() == optionTag) { + if (is<HTMLOptionElement>(m_tree.currentStackItem().node())) { AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName()); - processEndTag(&endOption); + processEndTag(WTFMove(endOption)); } - m_tree.insertHTMLElement(token); + m_tree.insertHTMLElement(WTFMove(token)); return; } - if (token->name() == optgroupTag) { - if (isHTMLOptionElement(m_tree.currentStackItem()->node())) { + if (token.name() == optgroupTag) { + if (is<HTMLOptionElement>(m_tree.currentStackItem().node())) { AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName()); - processEndTag(&endOption); + processEndTag(WTFMove(endOption)); } - if (isHTMLOptGroupElement(m_tree.currentStackItem()->node())) { + if (is<HTMLOptGroupElement>(m_tree.currentStackItem().node())) { AtomicHTMLToken endOptgroup(HTMLToken::EndTag, optgroupTag.localName()); - processEndTag(&endOptgroup); + processEndTag(WTFMove(endOptgroup)); } - m_tree.insertHTMLElement(token); + m_tree.insertHTMLElement(WTFMove(token)); return; } - if (token->name() == selectTag) { + if (token.name() == selectTag) { parseError(token); AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName()); - processEndTag(&endSelect); + processEndTag(WTFMove(endSelect)); return; } - if (token->name() == inputTag - || token->name() == keygenTag - || token->name() == textareaTag) { + if (token.name() == inputTag || token.name() == keygenTag || token.name() == textareaTag) { parseError(token); - if (!m_tree.openElements()->inSelectScope(selectTag)) { + if (!m_tree.openElements().inSelectScope(selectTag)) { ASSERT(isParsingFragment()); return; } AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName()); - processEndTag(&endSelect); - processStartTag(token); + processEndTag(WTFMove(endSelect)); + processStartTag(WTFMove(token)); return; } - if (token->name() == scriptTag) { - bool didProcess = processStartTagForInHead(token); + if (token.name() == scriptTag) { + bool didProcess = processStartTagForInHead(WTFMove(token)); ASSERT_UNUSED(didProcess, didProcess); return; } -#if ENABLE(TEMPLATE_ELEMENT) - if (token->name() == templateTag) { - processTemplateStartTag(token); + if (token.name() == templateTag) { + processTemplateStartTag(WTFMove(token)); return; } -#endif break; case InsertionMode::InTableText: defaultForInTableText(); - processStartTag(token); + processStartTag(WTFMove(token)); break; case InsertionMode::Text: ASSERT_NOT_REACHED(); break; case InsertionMode::TemplateContents: -#if ENABLE(TEMPLATE_ELEMENT) - if (token->name() == templateTag) { - processTemplateStartTag(token); + if (token.name() == templateTag) { + processTemplateStartTag(WTFMove(token)); return; } - if (token->name() == linkTag - || token->name() == scriptTag - || token->name() == styleTag - || token->name() == metaTag) { - processStartTagForInHead(token); + if (token.name() == linkTag + || token.name() == scriptTag + || token.name() == styleTag + || token.name() == metaTag) { + processStartTagForInHead(WTFMove(token)); return; } InsertionMode insertionMode = InsertionMode::TemplateContents; - if (token->name() == frameTag) - insertionMode = InsertionMode::InFrameset; - else if (token->name() == colTag) + if (token.name() == colTag) insertionMode = InsertionMode::InColumnGroup; - else if (isCaptionColOrColgroupTag(token->name()) || isTableBodyContextTag(token->name())) + else if (isCaptionColOrColgroupTag(token.name()) || isTableBodyContextTag(token.name())) insertionMode = InsertionMode::InTable; - else if (token->name() == trTag) + else if (token.name() == trTag) insertionMode = InsertionMode::InTableBody; - else if (isTableCellContextTag(token->name())) + else if (isTableCellContextTag(token.name())) insertionMode = InsertionMode::InRow; else insertionMode = InsertionMode::InBody; @@ -1468,64 +1363,57 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken* token) ASSERT(insertionMode != InsertionMode::TemplateContents); ASSERT(m_templateInsertionModes.last() == InsertionMode::TemplateContents); m_templateInsertionModes.last() = insertionMode; - setInsertionMode(insertionMode); + m_insertionMode = insertionMode; - processStartTag(token); -#else - ASSERT_NOT_REACHED(); -#endif + processStartTag(WTFMove(token)); break; } } -void HTMLTreeBuilder::processHtmlStartTagForInBody(AtomicHTMLToken* token) +void HTMLTreeBuilder::processHtmlStartTagForInBody(AtomicHTMLToken&& token) { parseError(token); -#if ENABLE(TEMPLATE_ELEMENT) - if (m_tree.openElements()->hasTemplateInHTMLScope()) { + if (m_tree.openElements().hasTemplateInHTMLScope()) { ASSERT(isParsingTemplateContents()); return; } -#endif - m_tree.insertHTMLHtmlStartTagInBody(token); + m_tree.insertHTMLHtmlStartTagInBody(WTFMove(token)); } -bool HTMLTreeBuilder::processBodyEndTagForInBody(AtomicHTMLToken* token) +bool HTMLTreeBuilder::processBodyEndTagForInBody(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::EndTag); - ASSERT(token->name() == bodyTag); - if (!m_tree.openElements()->inScope(bodyTag.localName())) { + ASSERT(token.type() == HTMLToken::EndTag); + ASSERT(token.name() == bodyTag); + if (!m_tree.openElements().inScope(bodyTag.localName())) { parseError(token); return false; } notImplemented(); // Emit a more specific parse error based on stack contents. - setInsertionMode(InsertionMode::AfterBody); + m_insertionMode = InsertionMode::AfterBody; return true; } -void HTMLTreeBuilder::processAnyOtherEndTagForInBody(AtomicHTMLToken* token) +void HTMLTreeBuilder::processAnyOtherEndTagForInBody(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::EndTag); - HTMLElementStack::ElementRecord* record = m_tree.openElements()->topRecord(); - while (1) { - RefPtr<HTMLStackItem> item = record->stackItem(); - if (item->matchesHTMLTag(token->name())) { - m_tree.generateImpliedEndTagsWithExclusion(token->name()); - if (!m_tree.currentStackItem()->matchesHTMLTag(token->name())) + ASSERT(token.type() == HTMLToken::EndTag); + for (auto* record = &m_tree.openElements().topRecord(); ; record = record->next()) { + HTMLStackItem& item = record->stackItem(); + if (item.matchesHTMLTag(token.name())) { + m_tree.generateImpliedEndTagsWithExclusion(token.name()); + if (!m_tree.currentStackItem().matchesHTMLTag(token.name())) parseError(token); - m_tree.openElements()->popUntilPopped(item->element()); + m_tree.openElements().popUntilPopped(item.element()); return; } - if (item->isSpecialNode()) { + if (isSpecialNode(item)) { parseError(token); return; } - record = record->next(); } } // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-inbody -void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken* token) +void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken& token) { // The adoption agency algorithm is N^2. We limit the number of iterations // to stop from hanging the whole browser. This limit is specified in the @@ -1537,43 +1425,43 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken* token) // 1, 2, 3 and 16 are covered by the for() loop. for (int i = 0; i < outerIterationLimit; ++i) { // 4. - Element* formattingElement = m_tree.activeFormattingElements()->closestElementInScopeWithName(token->name()); + Element* formattingElement = m_tree.activeFormattingElements().closestElementInScopeWithName(token.name()); // 4.a if (!formattingElement) - return processAnyOtherEndTagForInBody(token); + return processAnyOtherEndTagForInBody(WTFMove(token)); // 4.c - if ((m_tree.openElements()->contains(formattingElement)) && !m_tree.openElements()->inScope(formattingElement)) { + if ((m_tree.openElements().contains(*formattingElement)) && !m_tree.openElements().inScope(*formattingElement)) { parseError(token); notImplemented(); // Check the stack of open elements for a more specific parse error. return; } // 4.b - HTMLElementStack::ElementRecord* formattingElementRecord = m_tree.openElements()->find(formattingElement); + auto* formattingElementRecord = m_tree.openElements().find(*formattingElement); if (!formattingElementRecord) { parseError(token); - m_tree.activeFormattingElements()->remove(formattingElement); + m_tree.activeFormattingElements().remove(*formattingElement); return; } // 4.d - if (formattingElement != m_tree.currentElement()) + if (formattingElement != &m_tree.currentElement()) parseError(token); // 5. - HTMLElementStack::ElementRecord* furthestBlock = m_tree.openElements()->furthestBlockForFormattingElement(formattingElement); + auto* furthestBlock = m_tree.openElements().furthestBlockForFormattingElement(*formattingElement); // 6. if (!furthestBlock) { - m_tree.openElements()->popUntilPopped(formattingElement); - m_tree.activeFormattingElements()->remove(formattingElement); + m_tree.openElements().popUntilPopped(*formattingElement); + m_tree.activeFormattingElements().remove(*formattingElement); return; } // 7. - ASSERT(furthestBlock->isAbove(formattingElementRecord)); - RefPtr<HTMLStackItem> commonAncestor = formattingElementRecord->next()->stackItem(); + ASSERT(furthestBlock->isAbove(*formattingElementRecord)); + Ref<HTMLStackItem> commonAncestor = formattingElementRecord->next()->stackItem(); // 8. - HTMLFormattingElementList::Bookmark bookmark = m_tree.activeFormattingElements()->bookmarkFor(formattingElement); + HTMLFormattingElementList::Bookmark bookmark = m_tree.activeFormattingElements().bookmarkFor(*formattingElement); // 9. - HTMLElementStack::ElementRecord* node = furthestBlock; - HTMLElementStack::ElementRecord* nextNode = node->next(); - HTMLElementStack::ElementRecord* lastNode = furthestBlock; + auto* node = furthestBlock; + auto* nextNode = node->next(); + auto* lastNode = furthestBlock; // 9.1, 9.2, 9.3 and 9.11 are covered by the for() loop. for (int i = 0; i < innerIterationLimit; ++i) { // 9.4 @@ -1581,8 +1469,8 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken* token) ASSERT(node); nextNode = node->next(); // Save node->next() for the next iteration in case node is deleted in 9.5. // 9.5 - if (!m_tree.activeFormattingElements()->contains(node->element())) { - m_tree.openElements()->remove(node->element()); + if (!m_tree.activeFormattingElements().contains(node->element())) { + m_tree.openElements().remove(node->element()); node = 0; continue; } @@ -1590,33 +1478,31 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken* token) if (node == formattingElementRecord) break; // 9.7 - RefPtr<HTMLStackItem> newItem = m_tree.createElementFromSavedToken(node->stackItem().get()); + auto newItem = m_tree.createElementFromSavedToken(node->stackItem()); - HTMLFormattingElementList::Entry* nodeEntry = m_tree.activeFormattingElements()->find(node->element()); - nodeEntry->replaceElement(newItem); - node->replaceElement(newItem.release()); + HTMLFormattingElementList::Entry* nodeEntry = m_tree.activeFormattingElements().find(node->element()); + nodeEntry->replaceElement(newItem.copyRef()); + node->replaceElement(WTFMove(newItem)); // 9.8 if (lastNode == furthestBlock) - bookmark.moveToAfter(nodeEntry); + bookmark.moveToAfter(*nodeEntry); // 9.9 m_tree.reparent(*node, *lastNode); // 9.10 lastNode = node; } // 10. - m_tree.insertAlreadyParsedChild(*commonAncestor, *lastNode); + m_tree.insertAlreadyParsedChild(commonAncestor.get(), *lastNode); // 11. - RefPtr<HTMLStackItem> newItem = m_tree.createElementFromSavedToken(formattingElementRecord->stackItem().get()); - // 12. - m_tree.takeAllChildren(*newItem, *furthestBlock); - // 13. - m_tree.reparent(*furthestBlock, *newItem); + auto newItem = m_tree.createElementFromSavedToken(formattingElementRecord->stackItem()); + // 12. & 13. + m_tree.takeAllChildrenAndReparent(newItem, *furthestBlock); // 14. - m_tree.activeFormattingElements()->swapTo(formattingElement, newItem, bookmark); + m_tree.activeFormattingElements().swapTo(*formattingElement, newItem.copyRef(), bookmark); // 15. - m_tree.openElements()->remove(formattingElement); - m_tree.openElements()->insertAbove(newItem, furthestBlock); + m_tree.openElements().remove(*formattingElement); + m_tree.openElements().insertAbove(WTFMove(newItem), *furthestBlock); } } @@ -1624,719 +1510,691 @@ void HTMLTreeBuilder::resetInsertionModeAppropriately() { // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#reset-the-insertion-mode-appropriately bool last = false; - HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord(); - while (1) { - RefPtr<HTMLStackItem> item = nodeRecord->stackItem(); - if (item->node() == m_tree.openElements()->rootNode()) { + for (auto* record = &m_tree.openElements().topRecord(); ; record = record->next()) { + HTMLStackItem* item = &record->stackItem(); + if (&item->node() == &m_tree.openElements().rootNode()) { last = true; -#if ENABLE(TEMPLATE_ELEMENT) bool shouldCreateItem = isParsingFragment(); -#else - ASSERT(isParsingFragment()); - bool shouldCreateItem = true; -#endif if (shouldCreateItem) - item = HTMLStackItem::create(m_fragmentContext.contextElement(), HTMLStackItem::ItemForContextElement); + item = &m_fragmentContext.contextElementStackItem(); } -#if ENABLE(TEMPLATE_ELEMENT) - if (item->hasTagName(templateTag)) - return setInsertionMode(m_templateInsertionModes.last()); -#endif + + if (item->hasTagName(templateTag)) { + m_insertionMode = m_templateInsertionModes.last(); + return; + } + if (item->hasTagName(selectTag)) { -#if ENABLE(TEMPLATE_ELEMENT) if (!last) { - while (item->node() != m_tree.openElements()->rootNode() && !item->hasTagName(templateTag)) { - nodeRecord = nodeRecord->next(); - item = nodeRecord->stackItem(); - if (isHTMLTableElement(item->node())) - return setInsertionMode(InsertionMode::InSelectInTable); + while (&item->node() != &m_tree.openElements().rootNode() && !item->hasTagName(templateTag)) { + record = record->next(); + item = &record->stackItem(); + if (is<HTMLTableElement>(item->node())) { + m_insertionMode = InsertionMode::InSelectInTable; + return; + } } } -#endif - return setInsertionMode(InsertionMode::InSelect); - } - if (item->hasTagName(tdTag) || item->hasTagName(thTag)) - return setInsertionMode(InsertionMode::InCell); - if (item->hasTagName(trTag)) - return setInsertionMode(InsertionMode::InRow); - if (item->hasTagName(tbodyTag) || item->hasTagName(theadTag) || item->hasTagName(tfootTag)) - return setInsertionMode(InsertionMode::InTableBody); - if (item->hasTagName(captionTag)) - return setInsertionMode(InsertionMode::InCaption); + m_insertionMode = InsertionMode::InSelect; + return; + } + if (item->hasTagName(tdTag) || item->hasTagName(thTag)) { + m_insertionMode = InsertionMode::InCell; + return; + } + if (item->hasTagName(trTag)) { + m_insertionMode = InsertionMode::InRow; + return; + } + if (item->hasTagName(tbodyTag) || item->hasTagName(theadTag) || item->hasTagName(tfootTag)) { + m_insertionMode = InsertionMode::InTableBody; + return; + } + if (item->hasTagName(captionTag)) { + m_insertionMode = InsertionMode::InCaption; + return; + } if (item->hasTagName(colgroupTag)) { - return setInsertionMode(InsertionMode::InColumnGroup); + m_insertionMode = InsertionMode::InColumnGroup; + return; + } + if (is<HTMLTableElement>(item->node())) { + m_insertionMode = InsertionMode::InTable; + return; } - if (isHTMLTableElement(item->node())) - return setInsertionMode(InsertionMode::InTable); if (item->hasTagName(headTag)) { -#if ENABLE(TEMPLATE_ELEMENT) - if (!m_fragmentContext.fragment() || m_fragmentContext.contextElement() != item->node()) - return setInsertionMode(InsertionMode::InHead); -#endif - return setInsertionMode(InsertionMode::InBody); + if (!m_fragmentContext.fragment() || &m_fragmentContext.contextElement() != &item->node()) { + m_insertionMode = InsertionMode::InHead; + return; + } + m_insertionMode = InsertionMode::InBody; + return; + } + if (item->hasTagName(bodyTag)) { + m_insertionMode = InsertionMode::InBody; + return; } - if (item->hasTagName(bodyTag)) - return setInsertionMode(InsertionMode::InBody); if (item->hasTagName(framesetTag)) { - return setInsertionMode(InsertionMode::InFrameset); + m_insertionMode = InsertionMode::InFrameset; + return; } if (item->hasTagName(htmlTag)) { - if (m_tree.headStackItem()) - return setInsertionMode(InsertionMode::AfterHead); + if (m_tree.headStackItem()) { + m_insertionMode = InsertionMode::AfterHead; + return; + } ASSERT(isParsingFragment()); - return setInsertionMode(InsertionMode::BeforeHead); + m_insertionMode = InsertionMode::BeforeHead; + return; } if (last) { ASSERT(isParsingFragment()); - return setInsertionMode(InsertionMode::InBody); + m_insertionMode = InsertionMode::InBody; + return; } - nodeRecord = nodeRecord->next(); } } -void HTMLTreeBuilder::processEndTagForInTableBody(AtomicHTMLToken* token) +void HTMLTreeBuilder::processEndTagForInTableBody(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::EndTag); - if (isTableBodyContextTag(token->name())) { - if (!m_tree.openElements()->inTableScope(token->name())) { + ASSERT(token.type() == HTMLToken::EndTag); + if (isTableBodyContextTag(token.name())) { + if (!m_tree.openElements().inTableScope(token.name())) { parseError(token); return; } - m_tree.openElements()->popUntilTableBodyScopeMarker(); - m_tree.openElements()->pop(); - setInsertionMode(InsertionMode::InTable); + m_tree.openElements().popUntilTableBodyScopeMarker(); + m_tree.openElements().pop(); + m_insertionMode = InsertionMode::InTable; return; } - if (token->name() == tableTag) { + if (token.name() == tableTag) { // FIXME: This is slow. - if (!m_tree.openElements()->inTableScope(tbodyTag) && !m_tree.openElements()->inTableScope(theadTag) && !m_tree.openElements()->inTableScope(tfootTag)) { + if (!m_tree.openElements().inTableScope(tbodyTag) && !m_tree.openElements().inTableScope(theadTag) && !m_tree.openElements().inTableScope(tfootTag)) { ASSERT(isParsingFragmentOrTemplateContents()); parseError(token); return; } - m_tree.openElements()->popUntilTableBodyScopeMarker(); - ASSERT(isTableBodyContextTag(m_tree.currentStackItem()->localName())); - processFakeEndTag(m_tree.currentStackItem()->localName()); - processEndTag(token); + m_tree.openElements().popUntilTableBodyScopeMarker(); + ASSERT(isTableBodyContextTag(m_tree.currentStackItem().localName())); + processFakeEndTag(m_tree.currentStackItem().localName()); + processEndTag(WTFMove(token)); return; } - if (token->name() == bodyTag - || isCaptionColOrColgroupTag(token->name()) - || token->name() == htmlTag - || isTableCellContextTag(token->name()) - || token->name() == trTag) { + if (token.name() == bodyTag + || isCaptionColOrColgroupTag(token.name()) + || token.name() == htmlTag + || isTableCellContextTag(token.name()) + || token.name() == trTag) { parseError(token); return; } - processEndTagForInTable(token); + processEndTagForInTable(WTFMove(token)); } -void HTMLTreeBuilder::processEndTagForInRow(AtomicHTMLToken* token) +void HTMLTreeBuilder::processEndTagForInRow(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::EndTag); - if (token->name() == trTag) { + ASSERT(token.type() == HTMLToken::EndTag); + if (token.name() == trTag) { processTrEndTagForInRow(); return; } - if (token->name() == tableTag) { + if (token.name() == tableTag) { if (!processTrEndTagForInRow()) { ASSERT(isParsingFragmentOrTemplateContents()); return; } - ASSERT(insertionMode() == InsertionMode::InTableBody); - processEndTag(token); + ASSERT(m_insertionMode == InsertionMode::InTableBody); + processEndTag(WTFMove(token)); return; } - if (isTableBodyContextTag(token->name())) { - if (!m_tree.openElements()->inTableScope(token->name())) { + if (isTableBodyContextTag(token.name())) { + if (!m_tree.openElements().inTableScope(token.name())) { parseError(token); return; } processFakeEndTag(trTag); - ASSERT(insertionMode() == InsertionMode::InTableBody); - processEndTag(token); + ASSERT(m_insertionMode == InsertionMode::InTableBody); + processEndTag(WTFMove(token)); return; } - if (token->name() == bodyTag - || isCaptionColOrColgroupTag(token->name()) - || token->name() == htmlTag - || isTableCellContextTag(token->name())) { + if (token.name() == bodyTag + || isCaptionColOrColgroupTag(token.name()) + || token.name() == htmlTag + || isTableCellContextTag(token.name())) { parseError(token); return; } - processEndTagForInTable(token); + processEndTagForInTable(WTFMove(token)); } -void HTMLTreeBuilder::processEndTagForInCell(AtomicHTMLToken* token) +void HTMLTreeBuilder::processEndTagForInCell(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::EndTag); - if (isTableCellContextTag(token->name())) { - if (!m_tree.openElements()->inTableScope(token->name())) { + ASSERT(token.type() == HTMLToken::EndTag); + if (isTableCellContextTag(token.name())) { + if (!m_tree.openElements().inTableScope(token.name())) { parseError(token); return; } m_tree.generateImpliedEndTags(); - if (!m_tree.currentStackItem()->matchesHTMLTag(token->name())) + if (!m_tree.currentStackItem().matchesHTMLTag(token.name())) parseError(token); - m_tree.openElements()->popUntilPopped(token->name()); - m_tree.activeFormattingElements()->clearToLastMarker(); - setInsertionMode(InsertionMode::InRow); + m_tree.openElements().popUntilPopped(token.name()); + m_tree.activeFormattingElements().clearToLastMarker(); + m_insertionMode = InsertionMode::InRow; return; } - if (token->name() == bodyTag - || isCaptionColOrColgroupTag(token->name()) - || token->name() == htmlTag) { + if (token.name() == bodyTag + || isCaptionColOrColgroupTag(token.name()) + || token.name() == htmlTag) { parseError(token); return; } - if (token->name() == tableTag - || token->name() == trTag - || isTableBodyContextTag(token->name())) { - if (!m_tree.openElements()->inTableScope(token->name())) { -#if ENABLE(TEMPLATE_ELEMENT) - ASSERT(isTableBodyContextTag(token->name()) || m_tree.openElements()->inTableScope(templateTag) || isParsingFragment()); -#else - ASSERT(isTableBodyContextTag(token->name()) || isParsingFragment()); -#endif + if (token.name() == tableTag + || token.name() == trTag + || isTableBodyContextTag(token.name())) { + if (!m_tree.openElements().inTableScope(token.name())) { + ASSERT(isTableBodyContextTag(token.name()) || m_tree.openElements().inTableScope(templateTag) || isParsingFragment()); parseError(token); return; } closeTheCell(); - processEndTag(token); + processEndTag(WTFMove(token)); return; } - processEndTagForInBody(token); + processEndTagForInBody(WTFMove(token)); } -void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken* token) +void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::EndTag); - if (token->name() == bodyTag) { - processBodyEndTagForInBody(token); + ASSERT(token.type() == HTMLToken::EndTag); + if (token.name() == bodyTag) { + processBodyEndTagForInBody(WTFMove(token)); return; } - if (token->name() == htmlTag) { + if (token.name() == htmlTag) { AtomicHTMLToken endBody(HTMLToken::EndTag, bodyTag.localName()); - if (processBodyEndTagForInBody(&endBody)) - processEndTag(token); - return; - } - if (token->name() == addressTag - || token->name() == articleTag - || token->name() == asideTag - || token->name() == blockquoteTag - || token->name() == buttonTag - || token->name() == centerTag - || token->name() == detailsTag - || token->name() == dirTag - || token->name() == divTag - || token->name() == dlTag - || token->name() == fieldsetTag - || token->name() == figcaptionTag - || token->name() == figureTag - || token->name() == footerTag - || token->name() == headerTag - || token->name() == hgroupTag - || token->name() == listingTag - || token->name() == mainTag - || token->name() == menuTag - || token->name() == navTag - || token->name() == olTag - || token->name() == preTag - || token->name() == sectionTag - || token->name() == summaryTag - || token->name() == ulTag) { - if (!m_tree.openElements()->inScope(token->name())) { + if (processBodyEndTagForInBody(WTFMove(endBody))) + processEndTag(WTFMove(token)); + return; + } + if (token.name() == addressTag + || token.name() == articleTag + || token.name() == asideTag + || token.name() == blockquoteTag + || token.name() == buttonTag + || token.name() == centerTag + || token.name() == detailsTag + || token.name() == dirTag + || token.name() == divTag + || token.name() == dlTag + || token.name() == fieldsetTag + || token.name() == figcaptionTag + || token.name() == figureTag + || token.name() == footerTag + || token.name() == headerTag + || token.name() == hgroupTag + || token.name() == listingTag + || token.name() == mainTag + || token.name() == menuTag + || token.name() == navTag + || token.name() == olTag + || token.name() == preTag + || token.name() == sectionTag + || token.name() == summaryTag + || token.name() == ulTag) { + if (!m_tree.openElements().inScope(token.name())) { parseError(token); return; } m_tree.generateImpliedEndTags(); - if (!m_tree.currentStackItem()->matchesHTMLTag(token->name())) + if (!m_tree.currentStackItem().matchesHTMLTag(token.name())) parseError(token); - m_tree.openElements()->popUntilPopped(token->name()); + m_tree.openElements().popUntilPopped(token.name()); return; } - if (token->name() == formTag) { + if (token.name() == formTag) { if (!isParsingTemplateContents()) { - RefPtr<Element> node = m_tree.takeForm(); - if (!node || !m_tree.openElements()->inScope(node.get())) { + RefPtr<Element> formElement = m_tree.takeForm(); + if (!formElement || !m_tree.openElements().inScope(*formElement)) { parseError(token); return; } m_tree.generateImpliedEndTags(); - if (m_tree.currentNode() != node.get()) + if (&m_tree.currentNode() != formElement.get()) parseError(token); - m_tree.openElements()->remove(node.get()); + m_tree.openElements().remove(*formElement); } else { - if (!m_tree.openElements()->inScope(token->name())) { + if (!m_tree.openElements().inScope(token.name())) { parseError(token); return; } m_tree.generateImpliedEndTags(); - if (!m_tree.currentNode()->hasTagName(formTag)) + if (!m_tree.currentNode().hasTagName(formTag)) parseError(token); - m_tree.openElements()->popUntilPopped(token->name()); + m_tree.openElements().popUntilPopped(token.name()); } } - if (token->name() == pTag) { - if (!m_tree.openElements()->inButtonScope(token->name())) { + if (token.name() == pTag) { + if (!m_tree.openElements().inButtonScope(token.name())) { parseError(token); processFakeStartTag(pTag); - ASSERT(m_tree.openElements()->inScope(token->name())); - processEndTag(token); + ASSERT(m_tree.openElements().inScope(token.name())); + processEndTag(WTFMove(token)); return; } - m_tree.generateImpliedEndTagsWithExclusion(token->name()); - if (!m_tree.currentStackItem()->matchesHTMLTag(token->name())) + m_tree.generateImpliedEndTagsWithExclusion(token.name()); + if (!m_tree.currentStackItem().matchesHTMLTag(token.name())) parseError(token); - m_tree.openElements()->popUntilPopped(token->name()); + m_tree.openElements().popUntilPopped(token.name()); return; } - if (token->name() == liTag) { - if (!m_tree.openElements()->inListItemScope(token->name())) { + if (token.name() == liTag) { + if (!m_tree.openElements().inListItemScope(token.name())) { parseError(token); return; } - m_tree.generateImpliedEndTagsWithExclusion(token->name()); - if (!m_tree.currentStackItem()->matchesHTMLTag(token->name())) + m_tree.generateImpliedEndTagsWithExclusion(token.name()); + if (!m_tree.currentStackItem().matchesHTMLTag(token.name())) parseError(token); - m_tree.openElements()->popUntilPopped(token->name()); + m_tree.openElements().popUntilPopped(token.name()); return; } - if (token->name() == ddTag - || token->name() == dtTag) { - if (!m_tree.openElements()->inScope(token->name())) { + if (token.name() == ddTag || token.name() == dtTag) { + if (!m_tree.openElements().inScope(token.name())) { parseError(token); return; } - m_tree.generateImpliedEndTagsWithExclusion(token->name()); - if (!m_tree.currentStackItem()->matchesHTMLTag(token->name())) + m_tree.generateImpliedEndTagsWithExclusion(token.name()); + if (!m_tree.currentStackItem().matchesHTMLTag(token.name())) parseError(token); - m_tree.openElements()->popUntilPopped(token->name()); + m_tree.openElements().popUntilPopped(token.name()); return; } - if (isNumberedHeaderTag(token->name())) { - if (!m_tree.openElements()->hasNumberedHeaderElementInScope()) { + if (isNumberedHeaderTag(token.name())) { + if (!m_tree.openElements().hasNumberedHeaderElementInScope()) { parseError(token); return; } m_tree.generateImpliedEndTags(); - if (!m_tree.currentStackItem()->matchesHTMLTag(token->name())) + if (!m_tree.currentStackItem().matchesHTMLTag(token.name())) parseError(token); - m_tree.openElements()->popUntilNumberedHeaderElementPopped(); + m_tree.openElements().popUntilNumberedHeaderElementPopped(); return; } - if (isFormattingTag(token->name())) { + if (HTMLConstructionSite::isFormattingTag(token.name())) { callTheAdoptionAgency(token); return; } - if (token->name() == appletTag - || token->name() == marqueeTag - || token->name() == objectTag) { - if (!m_tree.openElements()->inScope(token->name())) { + if (token.name() == appletTag || token.name() == marqueeTag || token.name() == objectTag) { + if (!m_tree.openElements().inScope(token.name())) { parseError(token); return; } m_tree.generateImpliedEndTags(); - if (!m_tree.currentStackItem()->matchesHTMLTag(token->name())) + if (!m_tree.currentStackItem().matchesHTMLTag(token.name())) parseError(token); - m_tree.openElements()->popUntilPopped(token->name()); - m_tree.activeFormattingElements()->clearToLastMarker(); + m_tree.openElements().popUntilPopped(token.name()); + m_tree.activeFormattingElements().clearToLastMarker(); return; } - if (token->name() == brTag) { + if (token.name() == brTag) { parseError(token); processFakeStartTag(brTag); return; } -#if ENABLE(TEMPLATE_ELEMENT) - if (token->name() == templateTag) { - processTemplateEndTag(token); + if (token.name() == templateTag) { + processTemplateEndTag(WTFMove(token)); return; } -#endif - processAnyOtherEndTagForInBody(token); + processAnyOtherEndTagForInBody(WTFMove(token)); } bool HTMLTreeBuilder::processCaptionEndTagForInCaption() { - if (!m_tree.openElements()->inTableScope(captionTag.localName())) { + if (!m_tree.openElements().inTableScope(captionTag.localName())) { ASSERT(isParsingFragment()); // FIXME: parse error return false; } m_tree.generateImpliedEndTags(); - // FIXME: parse error if (!m_tree.currentStackItem()->hasTagName(captionTag)) - m_tree.openElements()->popUntilPopped(captionTag.localName()); - m_tree.activeFormattingElements()->clearToLastMarker(); - setInsertionMode(InsertionMode::InTable); + // FIXME: parse error if (!m_tree.currentStackItem().hasTagName(captionTag)) + m_tree.openElements().popUntilPopped(captionTag.localName()); + m_tree.activeFormattingElements().clearToLastMarker(); + m_insertionMode = InsertionMode::InTable; return true; } bool HTMLTreeBuilder::processTrEndTagForInRow() { - if (!m_tree.openElements()->inTableScope(trTag)) { + if (!m_tree.openElements().inTableScope(trTag)) { ASSERT(isParsingFragmentOrTemplateContents()); // FIXME: parse error return false; } - m_tree.openElements()->popUntilTableRowScopeMarker(); - ASSERT(m_tree.currentStackItem()->hasTagName(trTag)); - m_tree.openElements()->pop(); - setInsertionMode(InsertionMode::InTableBody); + m_tree.openElements().popUntilTableRowScopeMarker(); + ASSERT(m_tree.currentStackItem().hasTagName(trTag)); + m_tree.openElements().pop(); + m_insertionMode = InsertionMode::InTableBody; return true; } bool HTMLTreeBuilder::processTableEndTagForInTable() { - if (!m_tree.openElements()->inTableScope(tableTag)) { + if (!m_tree.openElements().inTableScope(tableTag)) { ASSERT(isParsingFragmentOrTemplateContents()); // FIXME: parse error. return false; } - m_tree.openElements()->popUntilPopped(tableTag.localName()); + m_tree.openElements().popUntilPopped(tableTag.localName()); resetInsertionModeAppropriately(); return true; } -void HTMLTreeBuilder::processEndTagForInTable(AtomicHTMLToken* token) +void HTMLTreeBuilder::processEndTagForInTable(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::EndTag); - if (token->name() == tableTag) { + ASSERT(token.type() == HTMLToken::EndTag); + if (token.name() == tableTag) { processTableEndTagForInTable(); return; } - if (token->name() == bodyTag - || isCaptionColOrColgroupTag(token->name()) - || token->name() == htmlTag - || isTableBodyContextTag(token->name()) - || isTableCellContextTag(token->name()) - || token->name() == trTag) { + if (token.name() == bodyTag + || isCaptionColOrColgroupTag(token.name()) + || token.name() == htmlTag + || isTableBodyContextTag(token.name()) + || isTableCellContextTag(token.name()) + || token.name() == trTag) { parseError(token); return; } parseError(token); // Is this redirection necessary here? HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree); - processEndTagForInBody(token); + processEndTagForInBody(WTFMove(token)); } -void HTMLTreeBuilder::processEndTag(AtomicHTMLToken* token) +void HTMLTreeBuilder::processEndTag(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::EndTag); - switch (insertionMode()) { + ASSERT(token.type() == HTMLToken::EndTag); + switch (m_insertionMode) { case InsertionMode::Initial: - ASSERT(insertionMode() == InsertionMode::Initial); defaultForInitial(); + ASSERT(m_insertionMode == InsertionMode::BeforeHTML); FALLTHROUGH; case InsertionMode::BeforeHTML: - ASSERT(insertionMode() == InsertionMode::BeforeHTML); - if (token->name() != headTag && token->name() != bodyTag && token->name() != htmlTag && token->name() != brTag) { + if (token.name() != headTag && token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) { parseError(token); return; } defaultForBeforeHTML(); + ASSERT(m_insertionMode == InsertionMode::BeforeHead); FALLTHROUGH; case InsertionMode::BeforeHead: - ASSERT(insertionMode() == InsertionMode::BeforeHead); - if (token->name() != headTag && token->name() != bodyTag && token->name() != htmlTag && token->name() != brTag) { + if (token.name() != headTag && token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) { parseError(token); return; } defaultForBeforeHead(); + ASSERT(m_insertionMode == InsertionMode::InHead); FALLTHROUGH; case InsertionMode::InHead: - ASSERT(insertionMode() == InsertionMode::InHead); // FIXME: This case should be broken out into processEndTagForInHead, // because other end tag cases now refer to it ("process the token for using the rules of the "in head" insertion mode"). // but because the logic falls through to InsertionMode::AfterHead, that gets a little messy. -#if ENABLE(TEMPLATE_ELEMENT) - if (token->name() == templateTag) { - processTemplateEndTag(token); + if (token.name() == templateTag) { + processTemplateEndTag(WTFMove(token)); return; } -#endif - if (token->name() == headTag) { - m_tree.openElements()->popHTMLHeadElement(); - setInsertionMode(InsertionMode::AfterHead); + if (token.name() == headTag) { + m_tree.openElements().popHTMLHeadElement(); + m_insertionMode = InsertionMode::AfterHead; return; } - if (token->name() != bodyTag && token->name() != htmlTag && token->name() != brTag) { + if (token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) { parseError(token); return; } defaultForInHead(); + ASSERT(m_insertionMode == InsertionMode::AfterHead); FALLTHROUGH; case InsertionMode::AfterHead: - ASSERT(insertionMode() == InsertionMode::AfterHead); - if (token->name() != bodyTag && token->name() != htmlTag && token->name() != brTag) { + if (token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) { parseError(token); return; } defaultForAfterHead(); + ASSERT(m_insertionMode == InsertionMode::InBody); FALLTHROUGH; case InsertionMode::InBody: - ASSERT(insertionMode() == InsertionMode::InBody); - processEndTagForInBody(token); + processEndTagForInBody(WTFMove(token)); break; case InsertionMode::InTable: - ASSERT(insertionMode() == InsertionMode::InTable); - processEndTagForInTable(token); + processEndTagForInTable(WTFMove(token)); break; case InsertionMode::InCaption: - ASSERT(insertionMode() == InsertionMode::InCaption); - if (token->name() == captionTag) { + if (token.name() == captionTag) { processCaptionEndTagForInCaption(); return; } - if (token->name() == tableTag) { + if (token.name() == tableTag) { parseError(token); if (!processCaptionEndTagForInCaption()) { ASSERT(isParsingFragment()); return; } - processEndTag(token); + processEndTag(WTFMove(token)); return; } - if (token->name() == bodyTag - || token->name() == colTag - || token->name() == colgroupTag - || token->name() == htmlTag - || isTableBodyContextTag(token->name()) - || isTableCellContextTag(token->name()) - || token->name() == trTag) { + if (token.name() == bodyTag + || token.name() == colTag + || token.name() == colgroupTag + || token.name() == htmlTag + || isTableBodyContextTag(token.name()) + || isTableCellContextTag(token.name()) + || token.name() == trTag) { parseError(token); return; } - processEndTagForInBody(token); + processEndTagForInBody(WTFMove(token)); break; case InsertionMode::InColumnGroup: - ASSERT(insertionMode() == InsertionMode::InColumnGroup); - if (token->name() == colgroupTag) { + if (token.name() == colgroupTag) { processColgroupEndTagForInColumnGroup(); return; } - if (token->name() == colTag) { + if (token.name() == colTag) { parseError(token); return; } -#if ENABLE(TEMPLATE_ELEMENT) - if (token->name() == templateTag) { - processTemplateEndTag(token); + if (token.name() == templateTag) { + processTemplateEndTag(WTFMove(token)); return; } -#endif if (!processColgroupEndTagForInColumnGroup()) { ASSERT(isParsingFragmentOrTemplateContents()); return; } - processEndTag(token); + processEndTag(WTFMove(token)); break; case InsertionMode::InRow: - ASSERT(insertionMode() == InsertionMode::InRow); - processEndTagForInRow(token); + processEndTagForInRow(WTFMove(token)); break; case InsertionMode::InCell: - ASSERT(insertionMode() == InsertionMode::InCell); - processEndTagForInCell(token); + processEndTagForInCell(WTFMove(token)); break; case InsertionMode::InTableBody: - ASSERT(insertionMode() == InsertionMode::InTableBody); - processEndTagForInTableBody(token); + processEndTagForInTableBody(WTFMove(token)); break; case InsertionMode::AfterBody: - ASSERT(insertionMode() == InsertionMode::AfterBody); - if (token->name() == htmlTag) { + if (token.name() == htmlTag) { if (isParsingFragment()) { parseError(token); return; } - setInsertionMode(InsertionMode::AfterAfterBody); + m_insertionMode = InsertionMode::AfterAfterBody; return; } FALLTHROUGH; case InsertionMode::AfterAfterBody: - ASSERT(insertionMode() == InsertionMode::AfterBody || insertionMode() == InsertionMode::AfterAfterBody); + ASSERT(m_insertionMode == InsertionMode::AfterBody || m_insertionMode == InsertionMode::AfterAfterBody); parseError(token); - setInsertionMode(InsertionMode::InBody); - processEndTag(token); + m_insertionMode = InsertionMode::InBody; + processEndTag(WTFMove(token)); break; case InsertionMode::InHeadNoscript: - ASSERT(insertionMode() == InsertionMode::InHeadNoscript); - if (token->name() == noscriptTag) { - ASSERT(m_tree.currentStackItem()->hasTagName(noscriptTag)); - m_tree.openElements()->pop(); - ASSERT(m_tree.currentStackItem()->hasTagName(headTag)); - setInsertionMode(InsertionMode::InHead); + if (token.name() == noscriptTag) { + ASSERT(m_tree.currentStackItem().hasTagName(noscriptTag)); + m_tree.openElements().pop(); + ASSERT(m_tree.currentStackItem().hasTagName(headTag)); + m_insertionMode = InsertionMode::InHead; return; } - if (token->name() != brTag) { + if (token.name() != brTag) { parseError(token); return; } defaultForInHeadNoscript(); - processToken(token); + processToken(WTFMove(token)); break; case InsertionMode::Text: - if (token->name() == scriptTag) { + if (token.name() == scriptTag) { // Pause ourselves so that parsing stops until the script can be processed by the caller. - ASSERT(m_tree.currentStackItem()->hasTagName(scriptTag)); + ASSERT(m_tree.currentStackItem().hasTagName(scriptTag)); if (scriptingContentIsAllowed(m_tree.parserContentPolicy())) - m_scriptToProcess = m_tree.currentElement(); - m_tree.openElements()->pop(); - setInsertionMode(m_originalInsertionMode); - - if (m_parser.tokenizer()) { - // This token will not have been created by the tokenizer if a - // self-closing script tag was encountered and pre-HTML5 parser - // quirks are enabled. We must set the tokenizer's state to - // DataState explicitly if the tokenizer didn't have a chance to. - ASSERT(m_parser.tokenizer()->state() == HTMLTokenizer::DataState || m_options.usePreHTML5ParserQuirks); - m_parser.tokenizer()->setState(HTMLTokenizer::DataState); - } + m_scriptToProcess = &downcast<HTMLScriptElement>(m_tree.currentElement()); + m_tree.openElements().pop(); + m_insertionMode = m_originalInsertionMode; + + // This token will not have been created by the tokenizer if a + // self-closing script tag was encountered and pre-HTML5 parser + // quirks are enabled. We must set the tokenizer's state to + // DataState explicitly if the tokenizer didn't have a chance to. + ASSERT(m_parser.tokenizer().isInDataState() || m_options.usePreHTML5ParserQuirks); + m_parser.tokenizer().setDataState(); return; } - m_tree.openElements()->pop(); - setInsertionMode(m_originalInsertionMode); + m_tree.openElements().pop(); + m_insertionMode = m_originalInsertionMode; break; case InsertionMode::InFrameset: - ASSERT(insertionMode() == InsertionMode::InFrameset); - if (token->name() == framesetTag) { - bool ignoreFramesetForFragmentParsing = m_tree.currentIsRootNode(); -#if ENABLE(TEMPLATE_ELEMENT) - ignoreFramesetForFragmentParsing = ignoreFramesetForFragmentParsing || m_tree.openElements()->hasTemplateInHTMLScope(); -#endif + if (token.name() == framesetTag) { + bool ignoreFramesetForFragmentParsing = m_tree.currentIsRootNode() || m_tree.openElements().hasTemplateInHTMLScope(); if (ignoreFramesetForFragmentParsing) { ASSERT(isParsingFragmentOrTemplateContents()); parseError(token); return; } - m_tree.openElements()->pop(); - if (!isParsingFragment() && !m_tree.currentStackItem()->hasTagName(framesetTag)) - setInsertionMode(InsertionMode::AfterFrameset); - return; - } -#if ENABLE(TEMPLATE_ELEMENT) - if (token->name() == templateTag) { - processTemplateEndTag(token); + m_tree.openElements().pop(); + if (!isParsingFragment() && !m_tree.currentStackItem().hasTagName(framesetTag)) + m_insertionMode = InsertionMode::AfterFrameset; return; } -#endif break; case InsertionMode::AfterFrameset: - ASSERT(insertionMode() == InsertionMode::AfterFrameset); - if (token->name() == htmlTag) { - setInsertionMode(InsertionMode::AfterAfterFrameset); + if (token.name() == htmlTag) { + m_insertionMode = InsertionMode::AfterAfterFrameset; return; } FALLTHROUGH; case InsertionMode::AfterAfterFrameset: - ASSERT(insertionMode() == InsertionMode::AfterFrameset || insertionMode() == InsertionMode::AfterAfterFrameset); + ASSERT(m_insertionMode == InsertionMode::AfterFrameset || m_insertionMode == InsertionMode::AfterAfterFrameset); parseError(token); break; case InsertionMode::InSelectInTable: - ASSERT(insertionMode() == InsertionMode::InSelectInTable); - if (token->name() == captionTag - || token->name() == tableTag - || isTableBodyContextTag(token->name()) - || token->name() == trTag - || isTableCellContextTag(token->name())) { + if (token.name() == captionTag + || token.name() == tableTag + || isTableBodyContextTag(token.name()) + || token.name() == trTag + || isTableCellContextTag(token.name())) { parseError(token); - if (m_tree.openElements()->inTableScope(token->name())) { + if (m_tree.openElements().inTableScope(token.name())) { AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName()); - processEndTag(&endSelect); - processEndTag(token); + processEndTag(WTFMove(endSelect)); + processEndTag(WTFMove(token)); } return; } FALLTHROUGH; case InsertionMode::InSelect: - ASSERT(insertionMode() == InsertionMode::InSelect || insertionMode() == InsertionMode::InSelectInTable); - if (token->name() == optgroupTag) { - if (isHTMLOptionElement(m_tree.currentStackItem()->node()) && m_tree.oneBelowTop() && isHTMLOptGroupElement(m_tree.oneBelowTop()->node())) + ASSERT(m_insertionMode == InsertionMode::InSelect || m_insertionMode == InsertionMode::InSelectInTable); + if (token.name() == optgroupTag) { + if (is<HTMLOptionElement>(m_tree.currentStackItem().node()) && m_tree.oneBelowTop() && is<HTMLOptGroupElement>(m_tree.oneBelowTop()->node())) processFakeEndTag(optionTag); - if (isHTMLOptGroupElement(m_tree.currentStackItem()->node())) { - m_tree.openElements()->pop(); + if (is<HTMLOptGroupElement>(m_tree.currentStackItem().node())) { + m_tree.openElements().pop(); return; } parseError(token); return; } - if (token->name() == optionTag) { - if (isHTMLOptionElement(m_tree.currentStackItem()->node())) { - m_tree.openElements()->pop(); + if (token.name() == optionTag) { + if (is<HTMLOptionElement>(m_tree.currentStackItem().node())) { + m_tree.openElements().pop(); return; } parseError(token); return; } - if (token->name() == selectTag) { - if (!m_tree.openElements()->inSelectScope(token->name())) { + if (token.name() == selectTag) { + if (!m_tree.openElements().inSelectScope(token.name())) { ASSERT(isParsingFragment()); parseError(token); return; } - m_tree.openElements()->popUntilPopped(selectTag.localName()); + m_tree.openElements().popUntilPopped(selectTag.localName()); resetInsertionModeAppropriately(); return; } -#if ENABLE(TEMPLATE_ELEMENT) - if (token->name() == templateTag) { - processTemplateEndTag(token); + if (token.name() == templateTag) { + processTemplateEndTag(WTFMove(token)); return; } -#endif break; case InsertionMode::InTableText: defaultForInTableText(); - processEndTag(token); + processEndTag(WTFMove(token)); break; case InsertionMode::TemplateContents: -#if ENABLE(TEMPLATE_ELEMENT) - if (token->name() == templateTag) { - processTemplateEndTag(token); + if (token.name() == templateTag) { + processTemplateEndTag(WTFMove(token)); return; } - - break; -#else - ASSERT_NOT_REACHED(); -#endif break; } } -void HTMLTreeBuilder::processComment(AtomicHTMLToken* token) +void HTMLTreeBuilder::processComment(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::Comment); + ASSERT(token.type() == HTMLToken::Comment); if (m_insertionMode == InsertionMode::Initial || m_insertionMode == InsertionMode::BeforeHTML || m_insertionMode == InsertionMode::AfterAfterBody || m_insertionMode == InsertionMode::AfterAfterFrameset) { - m_tree.insertCommentOnDocument(token); + m_tree.insertCommentOnDocument(WTFMove(token)); return; } if (m_insertionMode == InsertionMode::AfterBody) { - m_tree.insertCommentOnHTMLHtmlElement(token); + m_tree.insertCommentOnHTMLHtmlElement(WTFMove(token)); return; } if (m_insertionMode == InsertionMode::InTableText) { defaultForInTableText(); - processComment(token); + processComment(WTFMove(token)); return; } - m_tree.insertComment(token); + m_tree.insertComment(WTFMove(token)); } -void HTMLTreeBuilder::processCharacter(AtomicHTMLToken* token) +void HTMLTreeBuilder::processCharacter(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::Character); + ASSERT(token.type() == HTMLToken::Character); ExternalCharacterTokenBuffer buffer(token); processCharacterBuffer(buffer); } +#if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS) + // FIXME: Extract the following iOS-specific code into a separate file. -#if PLATFORM(IOS) // From the string 4089961010, creates a link of the form <a href="tel:4089961010">4089961010</a> and inserts it. void HTMLTreeBuilder::insertPhoneNumberLink(const String& string) { @@ -2344,13 +2202,13 @@ void HTMLTreeBuilder::insertPhoneNumberLink(const String& string) attributes.append(Attribute(HTMLNames::hrefAttr, ASCIILiteral("tel:") + string)); const AtomicString& aTagLocalName = aTag.localName(); - AtomicHTMLToken aStartToken(HTMLToken::StartTag, aTagLocalName, attributes); + AtomicHTMLToken aStartToken(HTMLToken::StartTag, aTagLocalName, WTFMove(attributes)); AtomicHTMLToken aEndToken(HTMLToken::EndTag, aTagLocalName); - processStartTag(&aStartToken); + processStartTag(WTFMove(aStartToken)); m_tree.executeQueuedTasks(); m_tree.insertTextNode(string); - processEndTag(&aEndToken); + processEndTag(WTFMove(aEndToken)); } // Locates the phone numbers in the string and deals with it @@ -2360,13 +2218,7 @@ void HTMLTreeBuilder::insertPhoneNumberLink(const String& string) // 4. Appends the rest of the string as a text node. void HTMLTreeBuilder::linkifyPhoneNumbers(const String& string) { - static DDDFACacheRef phoneNumbersCache = DDDFACacheCreateFromFramework(); - if (!phoneNumbersCache) { - m_tree.insertTextNode(string); - return; - } - - static DDDFAScannerRef phoneNumbersScanner = DDDFAScannerCreateFromCache(phoneNumbersCache); + ASSERT(TelephoneNumberDetector::isSupported()); // relativeStartPosition and relativeEndPosition are the endpoints of the phone number range, // relative to the scannerPosition @@ -2375,8 +2227,10 @@ void HTMLTreeBuilder::linkifyPhoneNumbers(const String& string) int relativeStartPosition = 0; int relativeEndPosition = 0; + auto characters = StringView(string).upconvertedCharacters(); + // While there's a phone number in the rest of the string... - while ((scannerPosition < length) && DDDFAScannerFirstResultInUnicharArray(phoneNumbersScanner, &string.characters()[scannerPosition], length - scannerPosition, &relativeStartPosition, &relativeEndPosition)) { + while (scannerPosition < length && TelephoneNumberDetector::find(&characters[scannerPosition], length - scannerPosition, &relativeStartPosition, &relativeEndPosition)) { // The convention in the Data Detectors framework is that the end position is the first character NOT in the phone number // (that is, the length of the range is relativeEndPosition - relativeStartPosition). So substract 1 to get the same // convention as the old WebCore phone number parser (so that the rest of the code is still valid if we want to go back @@ -2402,12 +2256,11 @@ void HTMLTreeBuilder::linkifyPhoneNumbers(const String& string) } // Looks at the ancestors of the element to determine whether we're inside an element which disallows parsing phone numbers. -static inline bool disallowTelephoneNumberParsing(const Node& node) +static inline bool disallowTelephoneNumberParsing(const ContainerNode& node) { return node.isLink() - || node.nodeType() == Node::COMMENT_NODE || node.hasTagName(scriptTag) - || (node.isHTMLElement() && toHTMLElement(node).isFormControlElement()) + || is<HTMLFormControlElement>(node) || node.hasTagName(styleTag) || node.hasTagName(ttTag) || node.hasTagName(preTag) @@ -2416,15 +2269,14 @@ static inline bool disallowTelephoneNumberParsing(const Node& node) static inline bool shouldParseTelephoneNumbersInNode(const ContainerNode& node) { - const ContainerNode* currentNode = &node; - do { - if (currentNode->isElementNode() && disallowTelephoneNumberParsing(*currentNode)) + for (const ContainerNode* ancestor = &node; ancestor; ancestor = ancestor->parentNode()) { + if (disallowTelephoneNumberParsing(*ancestor)) return false; - currentNode = currentNode->parentNode(); - } while (currentNode); + } return true; } -#endif // PLATFORM(IOS) + +#endif // ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS) void HTMLTreeBuilder::processCharacterBuffer(ExternalCharacterTokenBuffer& buffer) { @@ -2447,77 +2299,66 @@ ReprocessBuffer: return; } - switch (insertionMode()) { - case InsertionMode::Initial: { - ASSERT(insertionMode() == InsertionMode::Initial); + switch (m_insertionMode) { + case InsertionMode::Initial: buffer.skipLeadingWhitespace(); if (buffer.isEmpty()) return; defaultForInitial(); + ASSERT(m_insertionMode == InsertionMode::BeforeHTML); FALLTHROUGH; - } - case InsertionMode::BeforeHTML: { - ASSERT(insertionMode() == InsertionMode::BeforeHTML); + case InsertionMode::BeforeHTML: buffer.skipLeadingWhitespace(); if (buffer.isEmpty()) return; defaultForBeforeHTML(); + ASSERT(m_insertionMode == InsertionMode::BeforeHead); FALLTHROUGH; - } - case InsertionMode::BeforeHead: { - ASSERT(insertionMode() == InsertionMode::BeforeHead); + case InsertionMode::BeforeHead: buffer.skipLeadingWhitespace(); if (buffer.isEmpty()) return; defaultForBeforeHead(); + ASSERT(m_insertionMode == InsertionMode::InHead); FALLTHROUGH; - } case InsertionMode::InHead: { - ASSERT(insertionMode() == InsertionMode::InHead); String leadingWhitespace = buffer.takeLeadingWhitespace(); if (!leadingWhitespace.isEmpty()) m_tree.insertTextNode(leadingWhitespace, AllWhitespace); if (buffer.isEmpty()) return; defaultForInHead(); + ASSERT(m_insertionMode == InsertionMode::AfterHead); FALLTHROUGH; } case InsertionMode::AfterHead: { - ASSERT(insertionMode() == InsertionMode::AfterHead); String leadingWhitespace = buffer.takeLeadingWhitespace(); if (!leadingWhitespace.isEmpty()) m_tree.insertTextNode(leadingWhitespace, AllWhitespace); if (buffer.isEmpty()) return; defaultForAfterHead(); + ASSERT(m_insertionMode == InsertionMode::InBody); FALLTHROUGH; } case InsertionMode::InBody: case InsertionMode::InCaption: + case InsertionMode::InCell: case InsertionMode::TemplateContents: - case InsertionMode::InCell: { -#if ENABLE(TEMPLATE_ELEMENT) - ASSERT(insertionMode() == InsertionMode::InBody || insertionMode() == InsertionMode::InCaption || insertionMode() == InsertionMode::InCell || insertionMode() == InsertionMode::TemplateContents); -#else - ASSERT(insertionMode() != InsertionMode::TemplateContents); - ASSERT(insertionMode() == InsertionMode::InBody || insertionMode() == InsertionMode::InCaption || insertionMode() == InsertionMode::InCell); -#endif processCharacterBufferForInBody(buffer); break; - } case InsertionMode::InTable: case InsertionMode::InTableBody: - case InsertionMode::InRow: { - ASSERT(insertionMode() == InsertionMode::InTable || insertionMode() == InsertionMode::InTableBody || insertionMode() == InsertionMode::InRow); + case InsertionMode::InRow: ASSERT(m_pendingTableCharacters.isEmpty()); - if (m_tree.currentStackItem()->isElementNode() - && (isHTMLTableElement(m_tree.currentStackItem()->node()) - || m_tree.currentStackItem()->hasTagName(HTMLNames::tbodyTag) - || m_tree.currentStackItem()->hasTagName(HTMLNames::tfootTag) - || m_tree.currentStackItem()->hasTagName(HTMLNames::theadTag) - || m_tree.currentStackItem()->hasTagName(HTMLNames::trTag))) { + if (is<HTMLTableElement>(m_tree.currentStackItem().node()) + || m_tree.currentStackItem().hasTagName(HTMLNames::tbodyTag) + || m_tree.currentStackItem().hasTagName(HTMLNames::tfootTag) + || m_tree.currentStackItem().hasTagName(HTMLNames::theadTag) + || m_tree.currentStackItem().hasTagName(HTMLNames::trTag)) { + m_originalInsertionMode = m_insertionMode; - setInsertionMode(InsertionMode::InTableText); + m_insertionMode = InsertionMode::InTableText; // Note that we fall through to the InsertionMode::InTableText case below. } else { HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree); @@ -2525,13 +2366,10 @@ ReprocessBuffer: break; } FALLTHROUGH; - } - case InsertionMode::InTableText: { + case InsertionMode::InTableText: buffer.giveRemainingTo(m_pendingTableCharacters); break; - } case InsertionMode::InColumnGroup: { - ASSERT(insertionMode() == InsertionMode::InColumnGroup); String leadingWhitespace = buffer.takeLeadingWhitespace(); if (!leadingWhitespace.isEmpty()) m_tree.insertTextNode(leadingWhitespace, AllWhitespace); @@ -2547,20 +2385,14 @@ ReprocessBuffer: goto ReprocessBuffer; } case InsertionMode::AfterBody: - case InsertionMode::AfterAfterBody: { - ASSERT(insertionMode() == InsertionMode::AfterBody || insertionMode() == InsertionMode::AfterAfterBody); + case InsertionMode::AfterAfterBody: // FIXME: parse error - setInsertionMode(InsertionMode::InBody); + m_insertionMode = InsertionMode::InBody; goto ReprocessBuffer; - break; - } - case InsertionMode::Text: { - ASSERT(insertionMode() == InsertionMode::Text); + case InsertionMode::Text: m_tree.insertTextNode(buffer.takeRemaining()); break; - } case InsertionMode::InHeadNoscript: { - ASSERT(insertionMode() == InsertionMode::InHeadNoscript); String leadingWhitespace = buffer.takeLeadingWhitespace(); if (!leadingWhitespace.isEmpty()) m_tree.insertTextNode(leadingWhitespace, AllWhitespace); @@ -2568,11 +2400,9 @@ ReprocessBuffer: return; defaultForInHeadNoscript(); goto ReprocessBuffer; - break; } case InsertionMode::InFrameset: case InsertionMode::AfterFrameset: { - ASSERT(insertionMode() == InsertionMode::InFrameset || insertionMode() == InsertionMode::AfterFrameset || insertionMode() == InsertionMode::AfterAfterFrameset); String leadingWhitespace = buffer.takeRemainingWhitespace(); if (!leadingWhitespace.isEmpty()) m_tree.insertTextNode(leadingWhitespace, AllWhitespace); @@ -2581,11 +2411,9 @@ ReprocessBuffer: break; } case InsertionMode::InSelectInTable: - case InsertionMode::InSelect: { - ASSERT(insertionMode() == InsertionMode::InSelect || insertionMode() == InsertionMode::InSelectInTable); + case InsertionMode::InSelect: m_tree.insertTextNode(buffer.takeRemaining()); break; - } case InsertionMode::AfterAfterFrameset: { String leadingWhitespace = buffer.takeRemainingWhitespace(); if (!leadingWhitespace.isEmpty()) { @@ -2603,83 +2431,68 @@ void HTMLTreeBuilder::processCharacterBufferForInBody(ExternalCharacterTokenBuff { m_tree.reconstructTheActiveFormattingElements(); String characters = buffer.takeRemaining(); -#if PLATFORM(IOS) - if (!isParsingFragment() && m_tree.isTelephoneNumberParsingEnabled() && shouldParseTelephoneNumbersInNode(*m_tree.currentNode()) && DataDetectorsCoreLibrary()) +#if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS) + if (!isParsingFragment() && m_tree.isTelephoneNumberParsingEnabled() && shouldParseTelephoneNumbersInNode(m_tree.currentNode()) && TelephoneNumberDetector::isSupported()) linkifyPhoneNumbers(characters); else m_tree.insertTextNode(characters); #else m_tree.insertTextNode(characters); #endif - if (m_framesetOk && !isAllWhitespaceOrReplacementCharacters(characters)) m_framesetOk = false; } -void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken* token) +void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::EndOfFile); - switch (insertionMode()) { + ASSERT(token.type() == HTMLToken::EndOfFile); + switch (m_insertionMode) { case InsertionMode::Initial: - ASSERT(insertionMode() == InsertionMode::Initial); defaultForInitial(); + ASSERT(m_insertionMode == InsertionMode::BeforeHTML); FALLTHROUGH; case InsertionMode::BeforeHTML: - ASSERT(insertionMode() == InsertionMode::BeforeHTML); defaultForBeforeHTML(); + ASSERT(m_insertionMode == InsertionMode::BeforeHead); FALLTHROUGH; case InsertionMode::BeforeHead: - ASSERT(insertionMode() == InsertionMode::BeforeHead); defaultForBeforeHead(); + ASSERT(m_insertionMode == InsertionMode::InHead); FALLTHROUGH; case InsertionMode::InHead: - ASSERT(insertionMode() == InsertionMode::InHead); defaultForInHead(); + ASSERT(m_insertionMode == InsertionMode::AfterHead); FALLTHROUGH; case InsertionMode::AfterHead: - ASSERT(insertionMode() == InsertionMode::AfterHead); defaultForAfterHead(); + ASSERT(m_insertionMode == InsertionMode::InBody); FALLTHROUGH; case InsertionMode::InBody: case InsertionMode::InCell: case InsertionMode::InCaption: case InsertionMode::InRow: -#if ENABLE(TEMPLATE_ELEMENT) - ASSERT(insertionMode() == InsertionMode::InBody || insertionMode() == InsertionMode::InCell || insertionMode() == InsertionMode::InCaption || insertionMode() == InsertionMode::InRow || insertionMode() == InsertionMode::TemplateContents); -#else - ASSERT(insertionMode() != InsertionMode::TemplateContents); - ASSERT(insertionMode() == InsertionMode::InBody || insertionMode() == InsertionMode::InCell || insertionMode() == InsertionMode::InCaption || insertionMode() == InsertionMode::InRow); -#endif notImplemented(); // Emit parse error based on what elements are still open. -#if ENABLE(TEMPLATE_ELEMENT) - if (!m_templateInsertionModes.isEmpty()) - if (processEndOfFileForInTemplateContents(token)) + if (!m_templateInsertionModes.isEmpty()) { + if (processEndOfFileForInTemplateContents(WTFMove(token))) return; -#endif + } break; case InsertionMode::AfterBody: case InsertionMode::AfterAfterBody: - ASSERT(insertionMode() == InsertionMode::AfterBody || insertionMode() == InsertionMode::AfterAfterBody); break; case InsertionMode::InHeadNoscript: - ASSERT(insertionMode() == InsertionMode::InHeadNoscript); defaultForInHeadNoscript(); - processEndOfFile(token); + processEndOfFile(WTFMove(token)); return; case InsertionMode::AfterFrameset: case InsertionMode::AfterAfterFrameset: - ASSERT(insertionMode() == InsertionMode::AfterFrameset || insertionMode() == InsertionMode::AfterAfterFrameset); break; case InsertionMode::InColumnGroup: if (m_tree.currentIsRootNode()) { ASSERT(isParsingFragment()); return; // FIXME: Should we break here instead of returning? } -#if ENABLE(TEMPLATE_ELEMENT) - ASSERT(m_tree.currentNode()->hasTagName(colgroupTag) || m_tree.currentNode()->hasTagName(templateTag)); -#else - ASSERT(m_tree.currentNode()->hasTagName(colgroupTag)); -#endif + ASSERT(m_tree.currentNode().hasTagName(colgroupTag) || m_tree.currentNode().hasTagName(templateTag)); processColgroupEndTagForInColumnGroup(); FALLTHROUGH; case InsertionMode::InFrameset: @@ -2687,40 +2500,33 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken* token) case InsertionMode::InTableBody: case InsertionMode::InSelectInTable: case InsertionMode::InSelect: - ASSERT(insertionMode() == InsertionMode::InSelect || insertionMode() == InsertionMode::InSelectInTable || insertionMode() == InsertionMode::InTable || insertionMode() == InsertionMode::InFrameset || insertionMode() == InsertionMode::InTableBody || insertionMode() == InsertionMode::InColumnGroup); - if (m_tree.currentNode() != m_tree.openElements()->rootNode()) + ASSERT(m_insertionMode == InsertionMode::InSelect || m_insertionMode == InsertionMode::InSelectInTable || m_insertionMode == InsertionMode::InTable || m_insertionMode == InsertionMode::InFrameset || m_insertionMode == InsertionMode::InTableBody || m_insertionMode == InsertionMode::InColumnGroup); + if (&m_tree.currentNode() != &m_tree.openElements().rootNode()) parseError(token); - -#if ENABLE(TEMPLATE_ELEMENT) - if (!m_templateInsertionModes.isEmpty()) - if (processEndOfFileForInTemplateContents(token)) + if (!m_templateInsertionModes.isEmpty()) { + if (processEndOfFileForInTemplateContents(WTFMove(token))) return; -#endif + } break; case InsertionMode::InTableText: defaultForInTableText(); - processEndOfFile(token); + processEndOfFile(WTFMove(token)); return; case InsertionMode::Text: parseError(token); - if (m_tree.currentStackItem()->hasTagName(scriptTag)) + if (m_tree.currentStackItem().hasTagName(scriptTag)) notImplemented(); // mark the script element as "already started". - m_tree.openElements()->pop(); + m_tree.openElements().pop(); ASSERT(m_originalInsertionMode != InsertionMode::Text); - setInsertionMode(m_originalInsertionMode); - processEndOfFile(token); + m_insertionMode = m_originalInsertionMode; + processEndOfFile(WTFMove(token)); return; case InsertionMode::TemplateContents: -#if ENABLE(TEMPLATE_ELEMENT) - if (processEndOfFileForInTemplateContents(token)) + if (processEndOfFileForInTemplateContents(WTFMove(token))) return; break; -#else - ASSERT_NOT_REACHED(); -#endif } - ASSERT(m_tree.currentNode()); - m_tree.openElements()->popAll(); + m_tree.openElements().popAll(); } void HTMLTreeBuilder::defaultForInitial() @@ -2728,38 +2534,38 @@ void HTMLTreeBuilder::defaultForInitial() notImplemented(); m_tree.setDefaultCompatibilityMode(); // FIXME: parse error - setInsertionMode(InsertionMode::BeforeHTML); + m_insertionMode = InsertionMode::BeforeHTML; } void HTMLTreeBuilder::defaultForBeforeHTML() { AtomicHTMLToken startHTML(HTMLToken::StartTag, htmlTag.localName()); - m_tree.insertHTMLHtmlStartTagBeforeHTML(&startHTML); - setInsertionMode(InsertionMode::BeforeHead); + m_tree.insertHTMLHtmlStartTagBeforeHTML(WTFMove(startHTML)); + m_insertionMode = InsertionMode::BeforeHead; } void HTMLTreeBuilder::defaultForBeforeHead() { AtomicHTMLToken startHead(HTMLToken::StartTag, headTag.localName()); - processStartTag(&startHead); + processStartTag(WTFMove(startHead)); } void HTMLTreeBuilder::defaultForInHead() { AtomicHTMLToken endHead(HTMLToken::EndTag, headTag.localName()); - processEndTag(&endHead); + processEndTag(WTFMove(endHead)); } void HTMLTreeBuilder::defaultForInHeadNoscript() { AtomicHTMLToken endNoscript(HTMLToken::EndTag, noscriptTag.localName()); - processEndTag(&endNoscript); + processEndTag(WTFMove(endNoscript)); } void HTMLTreeBuilder::defaultForAfterHead() { AtomicHTMLToken startBody(HTMLToken::StartTag, bodyTag.localName()); - processStartTag(&startBody); + processStartTag(WTFMove(startBody)); m_framesetOk = true; } @@ -2773,135 +2579,149 @@ void HTMLTreeBuilder::defaultForInTableText() m_tree.reconstructTheActiveFormattingElements(); m_tree.insertTextNode(characters, NotAllWhitespace); m_framesetOk = false; - setInsertionMode(m_originalInsertionMode); + m_insertionMode = m_originalInsertionMode; return; } m_tree.insertTextNode(characters); - setInsertionMode(m_originalInsertionMode); + m_insertionMode = m_originalInsertionMode; } -bool HTMLTreeBuilder::processStartTagForInHead(AtomicHTMLToken* token) +bool HTMLTreeBuilder::processStartTagForInHead(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::StartTag); - if (token->name() == htmlTag) { - processHtmlStartTagForInBody(token); + ASSERT(token.type() == HTMLToken::StartTag); + if (token.name() == htmlTag) { + processHtmlStartTagForInBody(WTFMove(token)); return true; } - if (token->name() == baseTag - || token->name() == basefontTag - || token->name() == bgsoundTag - || token->name() == commandTag - || token->name() == linkTag - || token->name() == metaTag) { - m_tree.insertSelfClosingHTMLElement(token); + if (token.name() == baseTag + || token.name() == basefontTag + || token.name() == bgsoundTag + || token.name() == commandTag + || token.name() == linkTag + || token.name() == metaTag) { + m_tree.insertSelfClosingHTMLElement(WTFMove(token)); // Note: The custom processing for the <meta> tag is done in HTMLMetaElement::process(). return true; } - if (token->name() == titleTag) { - processGenericRCDATAStartTag(token); + if (token.name() == titleTag) { + processGenericRCDATAStartTag(WTFMove(token)); return true; } - if (token->name() == noscriptTag) { + if (token.name() == noscriptTag) { if (m_options.scriptEnabled) { - processGenericRawTextStartTag(token); + processGenericRawTextStartTag(WTFMove(token)); return true; } - m_tree.insertHTMLElement(token); - setInsertionMode(InsertionMode::InHeadNoscript); + m_tree.insertHTMLElement(WTFMove(token)); + m_insertionMode = InsertionMode::InHeadNoscript; return true; } - if (token->name() == noframesTag || token->name() == styleTag) { - processGenericRawTextStartTag(token); + if (token.name() == noframesTag || token.name() == styleTag) { + processGenericRawTextStartTag(WTFMove(token)); return true; } - if (token->name() == scriptTag) { - processScriptStartTag(token); - if (m_options.usePreHTML5ParserQuirks && token->selfClosing()) + if (token.name() == scriptTag) { + bool isSelfClosing = token.selfClosing(); + processScriptStartTag(WTFMove(token)); + if (m_options.usePreHTML5ParserQuirks && isSelfClosing) processFakeEndTag(scriptTag); return true; } -#if ENABLE(TEMPLATE_ELEMENT) - if (token->name() == templateTag) { - processTemplateStartTag(token); + if (token.name() == templateTag) { + m_framesetOk = false; + processTemplateStartTag(WTFMove(token)); return true; } -#endif - if (token->name() == headTag) { + if (token.name() == headTag) { parseError(token); return true; } return false; } -void HTMLTreeBuilder::processGenericRCDATAStartTag(AtomicHTMLToken* token) +void HTMLTreeBuilder::processGenericRCDATAStartTag(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::StartTag); - m_tree.insertHTMLElement(token); - if (m_parser.tokenizer()) - m_parser.tokenizer()->setState(HTMLTokenizer::RCDATAState); + ASSERT(token.type() == HTMLToken::StartTag); + m_tree.insertHTMLElement(WTFMove(token)); + m_parser.tokenizer().setRCDATAState(); m_originalInsertionMode = m_insertionMode; - setInsertionMode(InsertionMode::Text); + m_insertionMode = InsertionMode::Text; } -void HTMLTreeBuilder::processGenericRawTextStartTag(AtomicHTMLToken* token) +void HTMLTreeBuilder::processGenericRawTextStartTag(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::StartTag); - m_tree.insertHTMLElement(token); - if (m_parser.tokenizer()) - m_parser.tokenizer()->setState(HTMLTokenizer::RAWTEXTState); + ASSERT(token.type() == HTMLToken::StartTag); + m_tree.insertHTMLElement(WTFMove(token)); + m_parser.tokenizer().setRAWTEXTState(); m_originalInsertionMode = m_insertionMode; - setInsertionMode(InsertionMode::Text); + m_insertionMode = InsertionMode::Text; } -void HTMLTreeBuilder::processScriptStartTag(AtomicHTMLToken* token) +void HTMLTreeBuilder::processScriptStartTag(AtomicHTMLToken&& token) { - ASSERT(token->type() == HTMLToken::StartTag); - m_tree.insertScriptElement(token); - if (m_parser.tokenizer()) - m_parser.tokenizer()->setState(HTMLTokenizer::ScriptDataState); + ASSERT(token.type() == HTMLToken::StartTag); + m_tree.insertScriptElement(WTFMove(token)); + m_parser.tokenizer().setScriptDataState(); m_originalInsertionMode = m_insertionMode; TextPosition position = m_parser.textPosition(); m_scriptToProcessStartPosition = position; - setInsertionMode(InsertionMode::Text); + m_insertionMode = InsertionMode::Text; +} + +// http://www.whatwg.org/specs/web-apps/current-work/#adjusted-current-node +HTMLStackItem& HTMLTreeBuilder::adjustedCurrentStackItem() const +{ + ASSERT(!m_tree.isEmpty()); + if (isParsingFragment() && m_tree.openElements().hasOnlyOneElement()) + return m_fragmentContext.contextElementStackItem(); + + return m_tree.currentStackItem(); } // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#tree-construction -bool HTMLTreeBuilder::shouldProcessTokenInForeignContent(AtomicHTMLToken* token) +bool HTMLTreeBuilder::shouldProcessTokenInForeignContent(const AtomicHTMLToken& token) { if (m_tree.isEmpty()) return false; - HTMLStackItem* item = m_tree.currentStackItem(); - if (item->isInHTMLNamespace()) + HTMLStackItem& adjustedCurrentNode = adjustedCurrentStackItem(); + if (isInHTMLNamespace(adjustedCurrentNode)) return false; - if (HTMLElementStack::isMathMLTextIntegrationPoint(item)) { - if (token->type() == HTMLToken::StartTag - && token->name() != MathMLNames::mglyphTag - && token->name() != MathMLNames::malignmarkTag) + if (HTMLElementStack::isMathMLTextIntegrationPoint(adjustedCurrentNode)) { + if (token.type() == HTMLToken::StartTag + && token.name() != MathMLNames::mglyphTag + && token.name() != MathMLNames::malignmarkTag) return false; - if (token->type() == HTMLToken::Character) + if (token.type() == HTMLToken::Character) return false; } - if (item->hasTagName(MathMLNames::annotation_xmlTag) - && token->type() == HTMLToken::StartTag - && token->name() == SVGNames::svgTag) + if (adjustedCurrentNode.hasTagName(MathMLNames::annotation_xmlTag) + && token.type() == HTMLToken::StartTag + && token.name() == SVGNames::svgTag) return false; - if (HTMLElementStack::isHTMLIntegrationPoint(item)) { - if (token->type() == HTMLToken::StartTag) + if (HTMLElementStack::isHTMLIntegrationPoint(adjustedCurrentNode)) { + if (token.type() == HTMLToken::StartTag) return false; - if (token->type() == HTMLToken::Character) + if (token.type() == HTMLToken::Character) return false; } - if (token->type() == HTMLToken::EndOfFile) + if (token.type() == HTMLToken::EndOfFile) return false; return true; } -void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken* token) +static bool hasAttribute(const AtomicHTMLToken& token, const QualifiedName& name) +{ + return findAttribute(token.attributes(), name); +} + +void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken&& token) { - switch (token->type()) { + HTMLStackItem& adjustedCurrentNode = adjustedCurrentStackItem(); + + switch (token.type()) { case HTMLToken::Uninitialized: ASSERT_NOT_REACHED(); break; @@ -2909,52 +2729,52 @@ void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken* token) parseError(token); break; case HTMLToken::StartTag: { - if (token->name() == bTag - || token->name() == bigTag - || token->name() == blockquoteTag - || token->name() == bodyTag - || token->name() == brTag - || token->name() == centerTag - || token->name() == codeTag - || token->name() == ddTag - || token->name() == divTag - || token->name() == dlTag - || token->name() == dtTag - || token->name() == emTag - || token->name() == embedTag - || isNumberedHeaderTag(token->name()) - || token->name() == headTag - || token->name() == hrTag - || token->name() == iTag - || token->name() == imgTag - || token->name() == liTag - || token->name() == listingTag - || token->name() == menuTag - || token->name() == metaTag - || token->name() == nobrTag - || token->name() == olTag - || token->name() == pTag - || token->name() == preTag - || token->name() == rubyTag - || token->name() == sTag - || token->name() == smallTag - || token->name() == spanTag - || token->name() == strongTag - || token->name() == strikeTag - || token->name() == subTag - || token->name() == supTag - || token->name() == tableTag - || token->name() == ttTag - || token->name() == uTag - || token->name() == ulTag - || token->name() == varTag - || (token->name() == fontTag && (token->getAttributeItem(colorAttr) || token->getAttributeItem(faceAttr) || token->getAttributeItem(sizeAttr)))) { + if (token.name() == bTag + || token.name() == bigTag + || token.name() == blockquoteTag + || token.name() == bodyTag + || token.name() == brTag + || token.name() == centerTag + || token.name() == codeTag + || token.name() == ddTag + || token.name() == divTag + || token.name() == dlTag + || token.name() == dtTag + || token.name() == emTag + || token.name() == embedTag + || isNumberedHeaderTag(token.name()) + || token.name() == headTag + || token.name() == hrTag + || token.name() == iTag + || token.name() == imgTag + || token.name() == liTag + || token.name() == listingTag + || token.name() == menuTag + || token.name() == metaTag + || token.name() == nobrTag + || token.name() == olTag + || token.name() == pTag + || token.name() == preTag + || token.name() == rubyTag + || token.name() == sTag + || token.name() == smallTag + || token.name() == spanTag + || token.name() == strongTag + || token.name() == strikeTag + || token.name() == subTag + || token.name() == supTag + || token.name() == tableTag + || token.name() == ttTag + || token.name() == uTag + || token.name() == ulTag + || token.name() == varTag + || (token.name() == fontTag && (hasAttribute(token, colorAttr) || hasAttribute(token, faceAttr) || hasAttribute(token, sizeAttr)))) { parseError(token); - m_tree.openElements()->popUntilForeignContentScopeMarker(); - processStartTag(token); + m_tree.openElements().popUntilForeignContentScopeMarker(); + processStartTag(WTFMove(token)); return; } - const AtomicString& currentNamespace = m_tree.currentStackItem()->namespaceURI(); + const AtomicString& currentNamespace = adjustedCurrentNode.namespaceURI(); if (currentNamespace == MathMLNames::mathmlNamespaceURI) adjustMathMLAttributes(token); if (currentNamespace == SVGNames::svgNamespaceURI) { @@ -2962,44 +2782,44 @@ void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken* token) adjustSVGAttributes(token); } adjustForeignAttributes(token); - m_tree.insertForeignElement(token, currentNamespace); + m_tree.insertForeignElement(WTFMove(token), currentNamespace); break; } case HTMLToken::EndTag: { - if (m_tree.currentStackItem()->namespaceURI() == SVGNames::svgNamespaceURI) + if (adjustedCurrentNode.namespaceURI() == SVGNames::svgNamespaceURI) adjustSVGTagNameCase(token); - if (token->name() == SVGNames::scriptTag && m_tree.currentStackItem()->hasTagName(SVGNames::scriptTag)) { + if (token.name() == SVGNames::scriptTag && m_tree.currentStackItem().hasTagName(SVGNames::scriptTag)) { if (scriptingContentIsAllowed(m_tree.parserContentPolicy())) - m_scriptToProcess = m_tree.currentElement(); - m_tree.openElements()->pop(); + m_scriptToProcess = &downcast<SVGScriptElement>(m_tree.currentElement()); + m_tree.openElements().pop(); return; } - if (!m_tree.currentStackItem()->isInHTMLNamespace()) { + if (!isInHTMLNamespace(m_tree.currentStackItem())) { // FIXME: This code just wants an Element* iterator, instead of an ElementRecord* - HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord(); - if (!nodeRecord->stackItem()->hasLocalName(token->name())) + auto* nodeRecord = &m_tree.openElements().topRecord(); + if (nodeRecord->stackItem().localName() != token.name()) parseError(token); while (1) { - if (nodeRecord->stackItem()->hasLocalName(token->name())) { - m_tree.openElements()->popUntilPopped(nodeRecord->element()); + if (nodeRecord->stackItem().localName() == token.name()) { + m_tree.openElements().popUntilPopped(nodeRecord->element()); return; } nodeRecord = nodeRecord->next(); - if (nodeRecord->stackItem()->isInHTMLNamespace()) + if (isInHTMLNamespace(nodeRecord->stackItem())) break; } } // Otherwise, process the token according to the rules given in the section corresponding to the current insertion mode in HTML content. - processEndTag(token); + processEndTag(WTFMove(token)); break; } case HTMLToken::Comment: - m_tree.insertComment(token); + m_tree.insertComment(WTFMove(token)); return; case HTMLToken::Character: { - String characters = String(token->characters(), token->charactersLength()); + String characters = String(token.characters(), token.charactersLength()); m_tree.insertTextNode(characters); if (m_framesetOk && !isAllWhitespaceOrReplacementCharacters(characters)) m_framesetOk = false; @@ -3013,19 +2833,18 @@ void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken* token) void HTMLTreeBuilder::finished() { + ASSERT(!m_destroyed); + if (isParsingFragment()) return; -#if ENABLE(TEMPLATE_ELEMENT) ASSERT(m_templateInsertionModes.isEmpty()); -#endif - ASSERT(m_isAttached); - // Warning, this may detach the parser. Do not do anything else after this. m_tree.finishedParsing(); + // The tree builder might have been destroyed as an indirect result of finishing the parsing. } -void HTMLTreeBuilder::parseError(AtomicHTMLToken*) +inline void HTMLTreeBuilder::parseError(const AtomicHTMLToken&) { } |