diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-04-10 09:28:39 +0000 |
commit | 32761a6cee1d0dee366b885b7b9c777e67885688 (patch) | |
tree | d6bec92bebfb216f4126356e55518842c2f476a1 /Source/WebCore/html/parser/HTMLTreeBuilder.cpp | |
parent | a4e969f4965059196ca948db781e52f7cfebf19e (diff) | |
download | WebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz |
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Source/WebCore/html/parser/HTMLTreeBuilder.cpp')
-rw-r--r-- | Source/WebCore/html/parser/HTMLTreeBuilder.cpp | 2153 |
1 files changed, 1120 insertions, 1033 deletions
diff --git a/Source/WebCore/html/parser/HTMLTreeBuilder.cpp b/Source/WebCore/html/parser/HTMLTreeBuilder.cpp index dda0de851..46b3baf47 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, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2011 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,20 +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 "HTMLTableElement.h" +#include "HTMLTemplateElement.h" #include "LocalizedStrings.h" #include "NotImplemented.h" #include "XLinkNames.h" #include "XMLNSNames.h" #include "XMLNames.h" -#include <wtf/NeverDestroyed.h> +#include <wtf/MainThread.h> #include <wtf/unicode/CharacterNames.h> -#if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS) -#include "TelephoneNumberDetector.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)) #endif namespace WebCore { @@ -59,7 +81,7 @@ inline bool isHTMLSpaceOrReplacementCharacter(UChar character) } -static inline TextPosition uninitializedPositionValue1() +static TextPosition uninitializedPositionValue1() { return TextPosition(OrdinalNumber::fromOneBasedInt(-1), OrdinalNumber::first()); } @@ -86,7 +108,9 @@ 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) @@ -96,7 +120,9 @@ 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) @@ -117,27 +143,31 @@ static bool isNonAnchorNonNobrFormattingTag(const AtomicString& tagName) static bool isNonAnchorFormattingTag(const AtomicString& tagName) { - return tagName == nobrTag || isNonAnchorNonNobrFormattingTag(tagName); + return tagName == nobrTag + || isNonAnchorNonNobrFormattingTag(tagName); } -// https://html.spec.whatwg.org/multipage/syntax.html#formatting -bool HTMLConstructionSite::isFormattingTag(const AtomicString& tagName) +// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#formatting +static bool isFormattingTag(const AtomicString& tagName) { return tagName == aTag || isNonAnchorFormattingTag(tagName); } class HTMLTreeBuilder::ExternalCharacterTokenBuffer { + WTF_MAKE_NONCOPYABLE(ExternalCharacterTokenBuffer); public: - explicit ExternalCharacterTokenBuffer(AtomicHTMLToken& token) - : m_text(token.characters(), token.charactersLength()) - , m_isAll8BitData(token.charactersIsAll8BitData()) + explicit ExternalCharacterTokenBuffer(AtomicHTMLToken* token) + : m_current(token->characters()) + , m_end(m_current + token->charactersLength()) + , m_isAll8BitData(token->isAll8BitData()) { ASSERT(!isEmpty()); } explicit ExternalCharacterTokenBuffer(const String& string) - : m_text(string) - , m_isAll8BitData(m_text.is8Bit()) + : m_current(string.deprecatedCharacters()) + , m_end(m_current + string.length()) + , m_isAll8BitData(string.length() && string.is8Bit()) { ASSERT(!isEmpty()); } @@ -147,15 +177,15 @@ public: ASSERT(isEmpty()); } - bool isEmpty() const { return m_text.isEmpty(); } + bool isEmpty() const { return m_current == m_end; } bool isAll8BitData() const { return m_isAll8BitData; } void skipAtMostOneLeadingNewline() { ASSERT(!isEmpty()); - if (m_text[0] == '\n') - m_text = m_text.substring(1); + if (*m_current == '\n') + ++m_current; } void skipLeadingWhitespace() @@ -175,190 +205,190 @@ public: String takeRemaining() { - String result = makeString(m_text); - m_text = StringView(); - return result; + 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); } void giveRemainingTo(StringBuilder& recipient) { - recipient.append(m_text); - m_text = StringView(); + recipient.append(m_current, m_end - m_current); + m_current = m_end; } String takeRemainingWhitespace() { ASSERT(!isEmpty()); - Vector<LChar, 8> whitespace; + Vector<UChar> whitespace; do { - UChar character = m_text[0]; - if (isHTMLSpace(character)) - whitespace.append(character); - m_text = m_text.substring(1); - } while (!m_text.isEmpty()); - + UChar cc = *m_current++; + if (isHTMLSpace(cc)) + whitespace.append(cc); + } while (m_current < m_end); // 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); } private: - template<bool characterPredicate(UChar)> void skipLeading() + template<bool characterPredicate(UChar)> + void skipLeading() { ASSERT(!isEmpty()); - while (characterPredicate(m_text[0])) { - m_text = m_text.substring(1); - if (m_text.isEmpty()) + while (characterPredicate(*m_current)) { + if (++m_current == m_end) return; } } - template<bool characterPredicate(UChar)> String takeLeading() + template<bool characterPredicate(UChar)> + String takeLeading() { ASSERT(!isEmpty()); - StringView start = m_text; + const UChar* start = m_current; skipLeading<characterPredicate>(); - if (start.length() == m_text.length()) + if (start == m_current) return String(); - return makeString(start.substring(0, start.length() - m_text.length())); - } - - String makeString(StringView stringView) const - { - if (stringView.is8Bit() || !isAll8BitData()) - return stringView.toString(); - return String::make8BitFrom16BitSource(stringView.characters16(), stringView.length()); + if (isAll8BitData()) + return String::make8BitFrom16BitSource(start, m_current - start); + return String(start, m_current - start); } - StringView m_text; + const UChar* m_current; + const UChar* m_end; bool m_isAll8BitData; }; -inline bool HTMLTreeBuilder::isParsingTemplateContents() const -{ -#if ENABLE(TEMPLATE_ELEMENT) - return m_tree.openElements().hasTemplateInHTMLScope(); -#else - return false; -#endif -} - -inline bool HTMLTreeBuilder::isParsingFragmentOrTemplateContents() const -{ - return isParsingFragment() || isParsingTemplateContents(); -} HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser& parser, HTMLDocument& document, ParserContentPolicy parserContentPolicy, const HTMLParserOptions& options) - : m_parser(parser) - , m_options(options) + : m_framesetOk(true) +#ifndef NDEBUG + , m_isAttached(true) +#endif , 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 } -HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser& parser, DocumentFragment& fragment, Element& contextElement, ParserContentPolicy parserContentPolicy, const HTMLParserOptions& options) - : m_parser(parser) - , m_options(options) +// 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 , 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()); - - // 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)); + // 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); + if (contextElement->hasTagName(templateTag)) + m_templateInsertionModes.append(InsertionMode::TemplateContents); #endif - resetInsertionModeAppropriately(); + resetInsertionModeAppropriately(); + m_tree.setForm(!contextElement || isHTMLFormElement(contextElement) ? toHTMLFormElement(contextElement) : HTMLFormElement::findClosestFormAncestor(*contextElement)); + } +} - m_tree.setForm(is<HTMLFormElement>(contextElement) ? &downcast<HTMLFormElement>(contextElement) : HTMLFormElement::findClosestFormAncestor(contextElement)); +HTMLTreeBuilder::~HTMLTreeBuilder() +{ +} -#if !ASSERT_DISABLED - m_destructionProhibited = false; +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; #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 +HTMLTreeBuilder::FragmentParsingContext::~FragmentParsingContext() { - return contextElementStackItem().element(); } -inline HTMLStackItem& HTMLTreeBuilder::FragmentParsingContext::contextElementStackItem() const +PassRefPtr<Element> HTMLTreeBuilder::takeScriptToProcess(TextPosition& scriptStartPosition) { - ASSERT(m_fragment); - return *m_contextElementStackItem; -} - -RefPtr<Element> HTMLTreeBuilder::takeScriptToProcess(TextPosition& scriptStartPosition) -{ - ASSERT(!m_destroyed); - - if (!m_scriptToProcess) - return nullptr; - + ASSERT(m_scriptToProcess); // 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 WTFMove(m_scriptToProcess); + return m_scriptToProcess.release(); } -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); else processToken(token); - 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); + if (m_parser.tokenizer()) { + bool inForeignContent = !m_tree.isEmpty() + && !m_tree.currentStackItem()->isInHTMLNamespace() + && !HTMLElementStack::isHTMLIntegrationPoint(m_tree.currentStackItem()) + && !HTMLElementStack::isMathMLTextIntegrationPoint(m_tree.currentStackItem()); -#if !ASSERT_DISABLED - m_destructionProhibited = false; -#endif + m_parser.tokenizer()->setForceNullCharacterReplacement(m_insertionMode == InsertionMode::Text || inForeignContent); + m_parser.tokenizer()->setShouldAllowCDATA(inForeignContent); + } m_tree.executeQueuedTasks(); - // The tree builder might have been destroyed as an indirect result of executing the queued tasks. + // We might be detached now. } -void HTMLTreeBuilder::processToken(AtomicHTMLToken& token) +void HTMLTreeBuilder::processToken(AtomicHTMLToken* token) { - switch (token.type()) { + switch (token->type()) { case HTMLToken::Uninitialized: ASSERT_NOT_REACHED(); break; @@ -388,12 +418,12 @@ void HTMLTreeBuilder::processToken(AtomicHTMLToken& token) } } -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); - m_insertionMode = InsertionMode::BeforeHTML; + m_tree.insertDoctype(token); + setInsertionMode(InsertionMode::BeforeHTML); return; } if (m_insertionMode == InsertionMode::InTableText) { @@ -404,17 +434,17 @@ void HTMLTreeBuilder::processDoctypeToken(AtomicHTMLToken& token) parseError(token); } -void HTMLTreeBuilder::processFakeStartTag(const QualifiedName& tagName, Vector<Attribute>&& attributes) +void HTMLTreeBuilder::processFakeStartTag(const QualifiedName& tagName, const Vector<Attribute>& attributes) { // FIXME: We'll need a fancier conversion than just "localName" for SVG/MathML tags. - AtomicHTMLToken fakeToken(HTMLToken::StartTag, tagName.localName(), WTFMove(attributes)); - processStartTag(fakeToken); + AtomicHTMLToken fakeToken(HTMLToken::StartTag, tagName.localName(), attributes); + processStartTag(&fakeToken); } void HTMLTreeBuilder::processFakeEndTag(const AtomicString& tagName) { AtomicHTMLToken fakeToken(HTMLToken::EndTag, tagName); - processEndTag(fakeToken); + processEndTag(&fakeToken); } void HTMLTreeBuilder::processFakeEndTag(const QualifiedName& tagName) @@ -432,38 +462,41 @@ 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); + processEndTag(&endP); } -Vector<Attribute> HTMLTreeBuilder::attributesForIsindexInput(AtomicHTMLToken& token) +Vector<Attribute> HTMLTreeBuilder::attributesForIsindexInput(AtomicHTMLToken* token) { - Vector<Attribute> attributes = token.attributes(); - attributes.removeAllMatching([] (const Attribute& attribute) { - const QualifiedName& name = attribute.name(); - return name.matches(nameAttr) || name.matches(actionAttr) || name.matches(promptAttr); - }); + 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) +void HTMLTreeBuilder::processIsindexStartTagForInBody(AtomicHTMLToken* token) { - ASSERT(token.type() == HTMLToken::StartTag); - ASSERT(token.name() == isindexTag); + ASSERT(token->type() == HTMLToken::StartTag); + ASSERT(token->name() == isindexTag); parseError(token); if (m_tree.form() && !isParsingTemplateContents()) return; notImplemented(); // Acknowledge self-closing flag processFakeStartTag(formTag); - if (Attribute* actionAttribute = findAttribute(token.attributes(), actionAttr)) + Attribute* actionAttribute = token->getAttributeItem(actionAttr); + if (actionAttribute) m_tree.form()->setAttribute(actionAttr, actionAttribute->value()); processFakeStartTag(hrTag); processFakeStartTag(labelTag); - if (Attribute* promptAttribute = findAttribute(token.attributes(), promptAttr)) + Attribute* promptAttribute = token->getAttributeItem(promptAttr); + if (promptAttribute) processFakeCharacters(promptAttribute->value()); else processFakeCharacters(searchableIndexIntroduction()); @@ -476,357 +509,381 @@ void HTMLTreeBuilder::processIsindexStartTagForInBody(AtomicHTMLToken& token) 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; - for (auto* nodeRecord = &m_tree.openElements().topRecord(); ; nodeRecord = nodeRecord->next()) { - HTMLStackItem& item = nodeRecord->stackItem(); - if (shouldClose(item)) { - ASSERT(item.isElement()); - processFakeEndTag(item.localName()); + HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord(); + while (1) { + RefPtr<HTMLStackItem> item = nodeRecord->stackItem(); + if (shouldClose(item.get())) { + ASSERT(item->isElementNode()); + processFakeEndTag(item->localName()); break; } - if (isSpecialNode(item) && !item.hasTagName(addressTag) && !item.hasTagName(divTag) && !item.hasTagName(pTag)) + if (item->isSpecialNode() && !item->hasTagName(addressTag) && !item->hasTagName(divTag) && !item->hasTagName(pTag)) break; + nodeRecord = nodeRecord->next(); } processFakePEndTagIfPInButtonScope(); - m_tree.insertHTMLElement(&token); + m_tree.insertHTMLElement(token); } -template <typename TableQualifiedName> static HashMap<AtomicString, QualifiedName> createCaseMap(const TableQualifiedName* const names[], unsigned length) +typedef HashMap<AtomicString, QualifiedName> PrefixedNameToQualifiedNameMap; + +static void mapLoweredLocalNameToName(PrefixedNameToQualifiedNameMap* map, const QualifiedName* const names[], size_t length) { - HashMap<AtomicString, QualifiedName> map; - for (unsigned i = 0; i < length; ++i) { + for (size_t i = 0; i < length; ++i) { const QualifiedName& name = *names[i]; const AtomicString& localName = name.localName(); - AtomicString loweredLocalName = localName.convertToASCIILowercase(); + AtomicString loweredLocalName = localName.lower(); if (loweredLocalName != localName) - map.add(loweredLocalName, name); + map->add(loweredLocalName, name); } - return map; } -static void adjustSVGTagNameCase(AtomicHTMLToken& token) +static void adjustSVGTagNameCase(AtomicHTMLToken* token) { - static NeverDestroyed<HashMap<AtomicString, QualifiedName>> map = createCaseMap(SVGNames::getSVGTags(), SVGNames::SVGTagsCount); - const QualifiedName& casedName = map.get().get(token.name()); + static PrefixedNameToQualifiedNameMap* caseMap = 0; + if (!caseMap) { + caseMap = new PrefixedNameToQualifiedNameMap; + mapLoweredLocalNameToName(caseMap, SVGNames::getSVGTags(), SVGNames::SVGTagsCount); + } + + const QualifiedName& casedName = caseMap->get(token->name()); if (casedName.localName().isNull()) return; - token.setName(casedName.localName()); + token->setName(casedName.localName()); } -static inline void adjustAttributes(HashMap<AtomicString, QualifiedName>& map, AtomicHTMLToken& token) +template<const QualifiedName* const * getAttrs(), unsigned length> +static void adjustAttributes(AtomicHTMLToken* token) { - for (auto& attribute : token.attributes()) { - const QualifiedName& casedName = map.get(attribute.localName()); - if (!casedName.localName().isNull()) - attribute.parserSetName(casedName); + static PrefixedNameToQualifiedNameMap* caseMap = 0; + if (!caseMap) { + caseMap = new PrefixedNameToQualifiedNameMap; + mapLoweredLocalNameToName(caseMap, getAttrs(), length); } -} -template<const QualifiedName* const* attributesTable(), unsigned attributesTableLength> static void adjustAttributes(AtomicHTMLToken& token) -{ - static NeverDestroyed<HashMap<AtomicString, QualifiedName>> map = createCaseMap(attributesTable(), attributesTableLength); - adjustAttributes(map, token); + for (unsigned i = 0; i < token->attributes().size(); ++i) { + Attribute& tokenAttribute = token->attributes().at(i); + const QualifiedName& casedName = caseMap->get(tokenAttribute.localName()); + if (!casedName.localName().isNull()) + tokenAttribute.parserSetName(casedName); + } } -static inline void adjustSVGAttributes(AtomicHTMLToken& token) +static void adjustSVGAttributes(AtomicHTMLToken* token) { adjustAttributes<SVGNames::getSVGAttrs, SVGNames::SVGAttrsCount>(token); } -static inline void adjustMathMLAttributes(AtomicHTMLToken& token) +static void adjustMathMLAttributes(AtomicHTMLToken* token) { adjustAttributes<MathMLNames::getMathMLAttrs, MathMLNames::MathMLAttrsCount>(token); } -static void addNamesWithPrefix(HashMap<AtomicString, QualifiedName>& map, const AtomicString& prefix, const QualifiedName* const names[], unsigned length) +static void addNamesWithPrefix(PrefixedNameToQualifiedNameMap* map, const AtomicString& prefix, const QualifiedName* const names[], size_t length) { - for (unsigned i = 0; i < length; ++i) { + for (size_t i = 0; i < length; ++i) { const QualifiedName& name = *names[i]; const AtomicString& localName = name.localName(); - map.add(prefix + ':' + localName, QualifiedName(prefix, localName, name.namespaceURI())); + AtomicString prefixColonLocalName = prefix + ':' + localName; + QualifiedName nameWithPrefix(prefix, localName, name.namespaceURI()); + map->add(prefixColonLocalName, nameWithPrefix); } } -static HashMap<AtomicString, QualifiedName> createForeignAttributesMap() +static void adjustForeignAttributes(AtomicHTMLToken* token) { - HashMap<AtomicString, QualifiedName> map; + static PrefixedNameToQualifiedNameMap* map = 0; + if (!map) { + map = new PrefixedNameToQualifiedNameMap; - addNamesWithPrefix(map, xlinkAtom, XLinkNames::getXLinkAttrs(), XLinkNames::XLinkAttrsCount); - addNamesWithPrefix(map, xmlAtom, XMLNames::getXMLAttrs(), XMLNames::XMLAttrsCount); + addNamesWithPrefix(map, xlinkAtom, XLinkNames::getXLinkAttrs(), XLinkNames::XLinkAttrsCount); - map.add(WTF::xmlnsAtom, XMLNSNames::xmlnsAttr); - map.add("xmlns:xlink", QualifiedName(xmlnsAtom, xlinkAtom, XMLNSNames::xmlnsNamespaceURI)); + addNamesWithPrefix(map, xmlAtom, XMLNames::getXMLAttrs(), XMLNames::XMLAttrsCount); - return map; -} + map->add(WTF::xmlnsAtom, XMLNSNames::xmlnsAttr); + map->add("xmlns:xlink", QualifiedName(xmlnsAtom, xlinkAtom, XMLNSNames::xmlnsNamespaceURI)); + } -static void adjustForeignAttributes(AtomicHTMLToken& token) -{ - static NeverDestroyed<HashMap<AtomicString, QualifiedName>> map = createForeignAttributesMap(); - adjustAttributes(map, token); + 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); + } } -void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken& token) +void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken* token) { - ASSERT(token.type() == HTMLToken::StartTag); - if (token.name() == htmlTag) { + ASSERT(token->type() == HTMLToken::StartTag); + if (token->name() == htmlTag) { processHtmlStartTagForInBody(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) { + 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); 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(); + bool fragmentOrTemplateCase = !m_tree.openElements()->secondElementIsHTMLBodyElement() || m_tree.openElements()->hasOnlyOneElement(); #if ENABLE(TEMPLATE_ELEMENT) - fragmentOrTemplateCase = fragmentOrTemplateCase || m_tree.openElements().hasTemplateInHTMLScope(); + fragmentOrTemplateCase = fragmentOrTemplateCase || m_tree.openElements()->hasTemplateInHTMLScope(); #endif if (fragmentOrTemplateCase) { ASSERT(isParsingFragmentOrTemplateContents()); return; } m_framesetOk = false; - m_tree.insertHTMLBodyStartTagInBody(&token); + m_tree.insertHTMLBodyStartTagInBody(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); - 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) { + 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) { processFakePEndTagIfPInButtonScope(); - m_tree.insertHTMLElement(&token); + m_tree.insertHTMLElement(token); return; } - if (isNumberedHeaderTag(token.name())) { + if (isNumberedHeaderTag(token->name())) { processFakePEndTagIfPInButtonScope(); - if (isNumberedHeaderElement(m_tree.currentStackItem())) { + if (m_tree.currentStackItem()->isNumberedHeaderElement()) { parseError(token); - m_tree.openElements().pop(); + m_tree.openElements()->pop(); } - m_tree.insertHTMLElement(&token); + m_tree.insertHTMLElement(token); return; } - if (token.name() == preTag || token.name() == listingTag) { + if (token->name() == preTag || token->name() == listingTag) { processFakePEndTagIfPInButtonScope(); - m_tree.insertHTMLElement(&token); + m_tree.insertHTMLElement(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(token); return; } - if (token.name() == liTag) { + if (token->name() == liTag) { processCloseWhenNestedTag<isLi>(token); return; } - if (token.name() == ddTag || token.name() == dtTag) { + if (token->name() == ddTag || token->name() == dtTag) { processCloseWhenNestedTag<isDdOrDt>(token); return; } - if (token.name() == plaintextTag) { + if (token->name() == plaintextTag) { processFakePEndTagIfPInButtonScope(); - m_tree.insertHTMLElement(&token); - m_parser.tokenizer().setPLAINTEXTState(); + m_tree.insertHTMLElement(token); + if (m_parser.tokenizer()) + m_parser.tokenizer()->setState(HTMLTokenizer::PLAINTEXTState); 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? return; } m_tree.reconstructTheActiveFormattingElements(); - m_tree.insertHTMLElement(&token); + m_tree.insertHTMLElement(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(token); return; } - if (isNonAnchorNonNobrFormattingTag(token.name())) { + if (isNonAnchorNonNobrFormattingTag(token->name())) { m_tree.reconstructTheActiveFormattingElements(); - m_tree.insertFormattingElement(&token); + m_tree.insertFormattingElement(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(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(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(token); m_framesetOk = false; - m_insertionMode = InsertionMode::InTable; + setInsertionMode(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(token); m_framesetOk = false; return; } - if (token.name() == inputTag) { + if (token->name() == inputTag) { + Attribute* typeAttribute = token->getAttributeItem(typeAttr); m_tree.reconstructTheActiveFormattingElements(); - m_tree.insertSelfClosingHTMLElement(&token); - Attribute* typeAttribute = findAttribute(token.attributes(), typeAttr); - if (!typeAttribute || !equalLettersIgnoringASCIICase(typeAttribute->value(), "hidden")) + m_tree.insertSelfClosingHTMLElement(token); + if (!typeAttribute || !equalIgnoringCase(typeAttribute->value(), "hidden")) 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(token); return; } - if (token.name() == hrTag) { + if (token->name() == hrTag) { processFakePEndTagIfPInButtonScope(); - m_tree.insertSelfClosingHTMLElement(&token); + m_tree.insertSelfClosingHTMLElement(token); m_framesetOk = false; return; } - if (token.name() == isindexTag) { + if (token->name() == isindexTag) { processIsindexStartTagForInBody(token); return; } - if (token.name() == textareaTag) { - m_tree.insertHTMLElement(&token); + if (token->name() == textareaTag) { + m_tree.insertHTMLElement(token); m_shouldSkipLeadingNewline = true; - m_parser.tokenizer().setRCDATAState(); + if (m_parser.tokenizer()) + m_parser.tokenizer()->setState(HTMLTokenizer::RCDATAState); m_originalInsertionMode = m_insertionMode; m_framesetOk = false; - m_insertionMode = InsertionMode::Text; + setInsertionMode(InsertionMode::Text); return; } - if (token.name() == xmpTag) { + if (token->name() == xmpTag) { processFakePEndTagIfPInButtonScope(); m_tree.reconstructTheActiveFormattingElements(); m_framesetOk = false; processGenericRawTextStartTag(token); return; } - if (token.name() == iframeTag) { + if (token->name() == iframeTag) { m_framesetOk = false; processGenericRawTextStartTag(token); return; } - if (token.name() == noembedTag && m_options.pluginsEnabled) { + if (token->name() == noembedTag && m_options.pluginsEnabled) { processGenericRawTextStartTag(token); return; } - if (token.name() == noscriptTag && m_options.scriptEnabled) { + if (token->name() == noscriptTag && m_options.scriptEnabled) { processGenericRawTextStartTag(token); return; } - if (token.name() == selectTag) { + if (token->name() == selectTag) { m_tree.reconstructTheActiveFormattingElements(); - m_tree.insertHTMLElement(&token); + m_tree.insertHTMLElement(token); m_framesetOk = false; if (m_insertionMode == InsertionMode::InTable || m_insertionMode == InsertionMode::InCaption @@ -834,116 +891,105 @@ void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken& token) || m_insertionMode == InsertionMode::InTableBody || m_insertionMode == InsertionMode::InRow || m_insertionMode == InsertionMode::InCell) - m_insertionMode = InsertionMode::InSelectInTable; + setInsertionMode(InsertionMode::InSelectInTable); else - m_insertionMode = InsertionMode::InSelect; + setInsertionMode(InsertionMode::InSelect); return; } - if (token.name() == optgroupTag || token.name() == optionTag) { - if (is<HTMLOptionElement>(m_tree.currentStackItem().node())) { + if (token->name() == optgroupTag || token->name() == optionTag) { + if (isHTMLOptionElement(m_tree.currentStackItem()->node())) { AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName()); - processEndTag(endOption); + processEndTag(&endOption); } m_tree.reconstructTheActiveFormattingElements(); - m_tree.insertHTMLElement(&token); + m_tree.insertHTMLElement(token); return; } - if (token.name() == rbTag || token.name() == rtcTag) { - if (m_tree.openElements().inScope(rubyTag.localName())) { + if (token->name() == rpTag || token->name() == rtTag) { + if (m_tree.openElements()->inScope(rubyTag.localName())) { m_tree.generateImpliedEndTags(); - if (!m_tree.currentStackItem().hasTagName(rubyTag)) - parseError(token); - } - m_tree.insertHTMLElement(&token); - return; - } - 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)) + if (!m_tree.currentStackItem()->hasTagName(rubyTag)) parseError(token); } - m_tree.insertHTMLElement(&token); + m_tree.insertHTMLElement(token); return; } - if (token.name() == MathMLNames::mathTag.localName()) { + if (token->name() == MathMLNames::mathTag.localName()) { m_tree.reconstructTheActiveFormattingElements(); adjustMathMLAttributes(token); adjustForeignAttributes(token); - m_tree.insertForeignElement(&token, MathMLNames::mathmlNamespaceURI); + m_tree.insertForeignElement(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(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) { + if (token->name() == templateTag) { processTemplateStartTag(token); return; } #endif m_tree.reconstructTheActiveFormattingElements(); - m_tree.insertHTMLElement(&token); + m_tree.insertHTMLElement(token); } #if ENABLE(TEMPLATE_ELEMENT) - -void HTMLTreeBuilder::processTemplateStartTag(AtomicHTMLToken& token) +void HTMLTreeBuilder::processTemplateStartTag(AtomicHTMLToken* token) { - m_tree.activeFormattingElements().appendMarker(); - m_tree.insertHTMLElement(&token); + m_tree.activeFormattingElements()->appendMarker(); + m_tree.insertHTMLElement(token); m_templateInsertionModes.append(InsertionMode::TemplateContents); - m_insertionMode = InsertionMode::TemplateContents; + setInsertionMode(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(&endTemplate)) return false; processEndOfFile(token); return true; } - #endif bool HTMLTreeBuilder::processColgroupEndTagForInColumnGroup() { bool ignoreFakeEndTag = m_tree.currentIsRootNode(); #if ENABLE(TEMPLATE_ELEMENT) - ignoreFakeEndTag = ignoreFakeEndTag || m_tree.currentNode().hasTagName(templateTag); + ignoreFakeEndTag = ignoreFakeEndTag || m_tree.currentNode()->hasTagName(templateTag); #endif if (ignoreFakeEndTag) { @@ -951,60 +997,61 @@ bool HTMLTreeBuilder::processColgroupEndTagForInColumnGroup() // FIXME: parse error return false; } - m_tree.openElements().pop(); - m_insertionMode = InsertionMode::InTable; + m_tree.openElements()->pop(); + setInsertionMode(InsertionMode::InTable); return true; } // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#close-the-cell void HTMLTreeBuilder::closeTheCell() { - ASSERT(m_insertionMode == InsertionMode::InCell); - if (m_tree.openElements().inTableScope(tdTag)) { - ASSERT(!m_tree.openElements().inTableScope(thTag)); + ASSERT(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(m_insertionMode == InsertionMode::InRow); + ASSERT(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); - m_insertionMode = InsertionMode::InCaption; + ASSERT(token->type() == HTMLToken::StartTag); + if (token->name() == captionTag) { + m_tree.openElements()->popUntilTableScopeMarker(); + m_tree.activeFormattingElements()->appendMarker(); + m_tree.insertHTMLElement(token); + setInsertionMode(InsertionMode::InCaption); return; } - if (token.name() == colgroupTag) { - m_tree.openElements().popUntilTableScopeMarker(); - m_tree.insertHTMLElement(&token); - m_insertionMode = InsertionMode::InColumnGroup; + if (token->name() == colgroupTag) { + m_tree.openElements()->popUntilTableScopeMarker(); + m_tree.insertHTMLElement(token); + setInsertionMode(InsertionMode::InColumnGroup); return; } - if (token.name() == colTag) { + if (token->name() == colTag) { processFakeStartTag(colgroupTag); - ASSERT(m_insertionMode == InsertionMode::InColumnGroup); + ASSERT(insertionMode() == InsertionMode::InColumnGroup); processStartTag(token); return; } - if (isTableBodyContextTag(token.name())) { - m_tree.openElements().popUntilTableScopeMarker(); - m_tree.insertHTMLElement(&token); - m_insertionMode = InsertionMode::InTableBody; + if (isTableBodyContextTag(token->name())) { + m_tree.openElements()->popUntilTableScopeMarker(); + m_tree.insertHTMLElement(token); + setInsertionMode(InsertionMode::InTableBody); return; } - if (isTableCellContextTag(token.name()) || token.name() == trTag) { + if (isTableCellContextTag(token->name()) + || token->name() == trTag) { processFakeStartTag(tbodyTag); - ASSERT(m_insertionMode == InsertionMode::InTableBody); + ASSERT(insertionMode() == InsertionMode::InTableBody); processStartTag(token); return; } - if (token.name() == tableTag) { + if (token->name() == tableTag) { parseError(token); if (!processTableEndTagForInTable()) { ASSERT(isParsingFragmentOrTemplateContents()); @@ -1013,29 +1060,29 @@ void HTMLTreeBuilder::processStartTagForInTable(AtomicHTMLToken& token) processStartTag(token); return; } - if (token.name() == styleTag || token.name() == scriptTag) { + if (token->name() == styleTag || token->name() == scriptTag) { processStartTagForInHead(token); return; } - if (token.name() == inputTag) { - Attribute* typeAttribute = findAttribute(token.attributes(), typeAttr); - if (typeAttribute && equalLettersIgnoringASCIICase(typeAttribute->value(), "hidden")) { + if (token->name() == inputTag) { + Attribute* typeAttribute = token->getAttributeItem(typeAttr); + if (typeAttribute && equalIgnoringCase(typeAttribute->value(), "hidden")) { parseError(token); - m_tree.insertSelfClosingHTMLElement(&token); + m_tree.insertSelfClosingHTMLElement(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(token, true); + m_tree.openElements()->pop(); return; } #if ENABLE(TEMPLATE_ELEMENT) - if (token.name() == templateTag) { + if (token->name() == templateTag) { processTemplateStartTag(token); return; } @@ -1045,94 +1092,98 @@ void HTMLTreeBuilder::processStartTagForInTable(AtomicHTMLToken& token) processStartTagForInBody(token); } -void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token) +void HTMLTreeBuilder::processStartTag(AtomicHTMLToken* token) { - ASSERT(token.type() == HTMLToken::StartTag); - switch (m_insertionMode) { + ASSERT(token->type() == HTMLToken::StartTag); + switch (insertionMode()) { case InsertionMode::Initial: + ASSERT(insertionMode() == InsertionMode::Initial); defaultForInitial(); - ASSERT(m_insertionMode == InsertionMode::BeforeHTML); FALLTHROUGH; case InsertionMode::BeforeHTML: - if (token.name() == htmlTag) { - m_tree.insertHTMLHtmlStartTagBeforeHTML(&token); - m_insertionMode = InsertionMode::BeforeHead; + ASSERT(insertionMode() == InsertionMode::BeforeHTML); + if (token->name() == htmlTag) { + m_tree.insertHTMLHtmlStartTagBeforeHTML(token); + setInsertionMode(InsertionMode::BeforeHead); return; } defaultForBeforeHTML(); - ASSERT(m_insertionMode == InsertionMode::BeforeHead); FALLTHROUGH; case InsertionMode::BeforeHead: - if (token.name() == htmlTag) { + ASSERT(insertionMode() == InsertionMode::BeforeHead); + if (token->name() == htmlTag) { processHtmlStartTagForInBody(token); return; } - if (token.name() == headTag) { - m_tree.insertHTMLHeadElement(&token); - m_insertionMode = InsertionMode::InHead; + if (token->name() == headTag) { + m_tree.insertHTMLHeadElement(token); + setInsertionMode(InsertionMode::InHead); return; } defaultForBeforeHead(); - ASSERT(m_insertionMode == InsertionMode::InHead); FALLTHROUGH; case InsertionMode::InHead: + ASSERT(insertionMode() == InsertionMode::InHead); if (processStartTagForInHead(token)) return; defaultForInHead(); - ASSERT(m_insertionMode == InsertionMode::AfterHead); FALLTHROUGH; case InsertionMode::AfterHead: - if (token.name() == htmlTag) { + ASSERT(insertionMode() == InsertionMode::AfterHead); + if (token->name() == htmlTag) { processHtmlStartTagForInBody(token); return; } - if (token.name() == bodyTag) { + if (token->name() == bodyTag) { m_framesetOk = false; - m_tree.insertHTMLBodyElement(&token); - m_insertionMode = InsertionMode::InBody; + m_tree.insertHTMLBodyElement(token); + setInsertionMode(InsertionMode::InBody); return; } - if (token.name() == framesetTag) { - m_tree.insertHTMLElement(&token); - m_insertionMode = InsertionMode::InFrameset; + if (token->name() == framesetTag) { + m_tree.insertHTMLElement(token); + setInsertionMode(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 (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 + || token->name() == templateTag #endif - || token.name() == titleTag) { + || token->name() == titleTag) { parseError(token); - m_tree.openElements().pushHTMLHeadElement(m_tree.headStackItem()); + ASSERT(m_tree.head()); + m_tree.openElements()->pushHTMLHeadElement(m_tree.headStackItem()); processStartTagForInHead(token); - m_tree.openElements().removeHTMLHeadElement(&m_tree.head()); + 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); break; case InsertionMode::InTable: + ASSERT(insertionMode() == InsertionMode::InTable); processStartTagForInTable(token); break; case InsertionMode::InCaption: - if (isCaptionColOrColgroupTag(token.name()) - || isTableBodyContextTag(token.name()) - || isTableCellContextTag(token.name()) - || token.name() == trTag) { + ASSERT(insertionMode() == InsertionMode::InCaption); + if (isCaptionColOrColgroupTag(token->name()) + || isTableBodyContextTag(token->name()) + || isTableCellContextTag(token->name()) + || token->name() == trTag) { parseError(token); if (!processCaptionEndTagForInCaption()) { ASSERT(isParsingFragment()); @@ -1144,16 +1195,17 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token) processStartTagForInBody(token); break; case InsertionMode::InColumnGroup: - if (token.name() == htmlTag) { + ASSERT(insertionMode() == InsertionMode::InColumnGroup); + if (token->name() == htmlTag) { processHtmlStartTagForInBody(token); return; } - if (token.name() == colTag) { - m_tree.insertSelfClosingHTMLElement(&token); + if (token->name() == colTag) { + m_tree.insertSelfClosingHTMLElement(token); return; } #if ENABLE(TEMPLATE_ELEMENT) - if (token.name() == templateTag) { + if (token->name() == templateTag) { processTemplateStartTag(token); return; } @@ -1165,62 +1217,65 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token) processStartTag(token); break; case InsertionMode::InTableBody: - if (token.name() == trTag) { - m_tree.openElements().popUntilTableBodyScopeMarker(); // How is there ever anything to pop? - m_tree.insertHTMLElement(&token); - m_insertionMode = InsertionMode::InRow; + 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); return; } - if (isTableCellContextTag(token.name())) { + if (isTableCellContextTag(token->name())) { parseError(token); processFakeStartTag(trTag); - ASSERT(m_insertionMode == InsertionMode::InRow); + ASSERT(insertionMode() == InsertionMode::InRow); processStartTag(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()); + m_tree.openElements()->popUntilTableBodyScopeMarker(); + ASSERT(isTableBodyContextTag(m_tree.currentStackItem()->localName())); + processFakeEndTag(m_tree.currentStackItem()->localName()); processStartTag(token); return; } processStartTagForInTable(token); break; case InsertionMode::InRow: - if (isTableCellContextTag(token.name())) { - m_tree.openElements().popUntilTableRowScopeMarker(); - m_tree.insertHTMLElement(&token); - m_insertionMode = InsertionMode::InCell; - m_tree.activeFormattingElements().appendMarker(); + ASSERT(insertionMode() == InsertionMode::InRow); + if (isTableCellContextTag(token->name())) { + m_tree.openElements()->popUntilTableRowScopeMarker(); + m_tree.insertHTMLElement(token); + setInsertionMode(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(m_insertionMode == InsertionMode::InTableBody); + ASSERT(insertionMode() == InsertionMode::InTableBody); processStartTag(token); return; } processStartTagForInTable(token); break; case InsertionMode::InCell: - if (isCaptionColOrColgroupTag(token.name()) - || isTableCellContextTag(token.name()) - || token.name() == trTag - || isTableBodyContextTag(token.name())) { + ASSERT(insertionMode() == InsertionMode::InCell); + 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; @@ -1233,29 +1288,31 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token) break; case InsertionMode::AfterBody: case InsertionMode::AfterAfterBody: - if (token.name() == htmlTag) { + ASSERT(insertionMode() == InsertionMode::AfterBody || insertionMode() == InsertionMode::AfterAfterBody); + if (token->name() == htmlTag) { processHtmlStartTagForInBody(token); return; } - m_insertionMode = InsertionMode::InBody; + setInsertionMode(InsertionMode::InBody); processStartTag(token); break; case InsertionMode::InHeadNoscript: - if (token.name() == htmlTag) { + 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) { + if (token->name() == basefontTag + || token->name() == bgsoundTag + || token->name() == linkTag + || token->name() == metaTag + || token->name() == noframesTag + || token->name() == styleTag) { bool didProcess = processStartTagForInHead(token); ASSERT_UNUSED(didProcess, didProcess); return; } - if (token.name() == htmlTag || token.name() == noscriptTag) { + if (token->name() == htmlTag || token->name() == noscriptTag) { parseError(token); return; } @@ -1263,24 +1320,25 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token) processToken(token); break; case InsertionMode::InFrameset: - if (token.name() == htmlTag) { + ASSERT(insertionMode() == InsertionMode::InFrameset); + if (token->name() == htmlTag) { processHtmlStartTagForInBody(token); return; } - if (token.name() == framesetTag) { - m_tree.insertHTMLElement(&token); + if (token->name() == framesetTag) { + m_tree.insertHTMLElement(token); return; } - if (token.name() == frameTag) { - m_tree.insertSelfClosingHTMLElement(&token); + if (token->name() == frameTag) { + m_tree.insertSelfClosingHTMLElement(token); return; } - if (token.name() == noframesTag) { + if (token->name() == noframesTag) { processStartTagForInHead(token); return; } #if ENABLE(TEMPLATE_ELEMENT) - if (token.name() == templateTag) { + if (token->name() == templateTag) { processTemplateStartTag(token); return; } @@ -1289,78 +1347,83 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token) break; case InsertionMode::AfterFrameset: case InsertionMode::AfterAfterFrameset: - if (token.name() == htmlTag) { + ASSERT(insertionMode() == InsertionMode::AfterFrameset || insertionMode() == InsertionMode::AfterAfterFrameset); + if (token->name() == htmlTag) { processHtmlStartTagForInBody(token); return; } - if (token.name() == noframesTag) { + if (token->name() == noframesTag) { processStartTagForInHead(token); return; } parseError(token); break; case InsertionMode::InSelectInTable: - if (token.name() == captionTag - || token.name() == tableTag - || isTableBodyContextTag(token.name()) - || token.name() == trTag - || isTableCellContextTag(token.name())) { + ASSERT(insertionMode() == InsertionMode::InSelectInTable); + 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); + processEndTag(&endSelect); processStartTag(token); return; } FALLTHROUGH; case InsertionMode::InSelect: - if (token.name() == htmlTag) { + ASSERT(insertionMode() == InsertionMode::InSelect || insertionMode() == InsertionMode::InSelectInTable); + if (token->name() == htmlTag) { processHtmlStartTagForInBody(token); return; } - if (token.name() == optionTag) { - if (is<HTMLOptionElement>(m_tree.currentStackItem().node())) { + if (token->name() == optionTag) { + if (isHTMLOptionElement(m_tree.currentStackItem()->node())) { AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName()); - processEndTag(endOption); + processEndTag(&endOption); } - m_tree.insertHTMLElement(&token); + m_tree.insertHTMLElement(token); return; } - if (token.name() == optgroupTag) { - if (is<HTMLOptionElement>(m_tree.currentStackItem().node())) { + if (token->name() == optgroupTag) { + if (isHTMLOptionElement(m_tree.currentStackItem()->node())) { AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName()); - processEndTag(endOption); + processEndTag(&endOption); } - if (is<HTMLOptGroupElement>(m_tree.currentStackItem().node())) { + if (isHTMLOptGroupElement(m_tree.currentStackItem()->node())) { AtomicHTMLToken endOptgroup(HTMLToken::EndTag, optgroupTag.localName()); - processEndTag(endOptgroup); + processEndTag(&endOptgroup); } - m_tree.insertHTMLElement(&token); + m_tree.insertHTMLElement(token); return; } - if (token.name() == selectTag) { + if (token->name() == selectTag) { parseError(token); AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName()); - processEndTag(endSelect); + processEndTag(&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); + processEndTag(&endSelect); processStartTag(token); return; } - if (token.name() == scriptTag) { + if (token->name() == scriptTag) { bool didProcess = processStartTagForInHead(token); ASSERT_UNUSED(didProcess, didProcess); return; } #if ENABLE(TEMPLATE_ELEMENT) - if (token.name() == templateTag) { + if (token->name() == templateTag) { processTemplateStartTag(token); return; } @@ -1373,31 +1436,31 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token) case InsertionMode::Text: ASSERT_NOT_REACHED(); break; -#if ENABLE(TEMPLATE_ELEMENT) case InsertionMode::TemplateContents: - if (token.name() == templateTag) { +#if ENABLE(TEMPLATE_ELEMENT) + if (token->name() == templateTag) { processTemplateStartTag(token); return; } - if (token.name() == linkTag - || token.name() == scriptTag - || token.name() == styleTag - || token.name() == metaTag) { + if (token->name() == linkTag + || token->name() == scriptTag + || token->name() == styleTag + || token->name() == metaTag) { processStartTagForInHead(token); return; } InsertionMode insertionMode = InsertionMode::TemplateContents; - if (token.name() == frameTag) + if (token->name() == frameTag) insertionMode = InsertionMode::InFrameset; - else if (token.name() == colTag) + else 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; @@ -1405,60 +1468,64 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token) ASSERT(insertionMode != InsertionMode::TemplateContents); ASSERT(m_templateInsertionModes.last() == InsertionMode::TemplateContents); m_templateInsertionModes.last() = insertionMode; - m_insertionMode = insertionMode; + setInsertionMode(insertionMode); processStartTag(token); - break; +#else + ASSERT_NOT_REACHED(); #endif + 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(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. - m_insertionMode = InsertionMode::AfterBody; + setInsertionMode(InsertionMode::AfterBody); return true; } -void HTMLTreeBuilder::processAnyOtherEndTagForInBody(AtomicHTMLToken& token) +void HTMLTreeBuilder::processAnyOtherEndTagForInBody(AtomicHTMLToken* token) { - 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())) + 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())) parseError(token); - m_tree.openElements().popUntilPopped(&item.element()); + m_tree.openElements()->popUntilPopped(item->element()); return; } - if (isSpecialNode(item)) { + if (item->isSpecialNode()) { 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 @@ -1470,43 +1537,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); // 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 - auto* formattingElementRecord = m_tree.openElements().find(formattingElement); + HTMLElementStack::ElementRecord* 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. - auto* furthestBlock = m_tree.openElements().furthestBlockForFormattingElement(formattingElement); + HTMLElementStack::ElementRecord* 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)); - Ref<HTMLStackItem> commonAncestor = formattingElementRecord->next()->stackItem(); + RefPtr<HTMLStackItem> commonAncestor = formattingElementRecord->next()->stackItem(); // 8. - HTMLFormattingElementList::Bookmark bookmark = m_tree.activeFormattingElements().bookmarkFor(formattingElement); + HTMLFormattingElementList::Bookmark bookmark = m_tree.activeFormattingElements()->bookmarkFor(formattingElement); // 9. - auto* node = furthestBlock; - auto* nextNode = node->next(); - auto* lastNode = furthestBlock; + HTMLElementStack::ElementRecord* node = furthestBlock; + HTMLElementStack::ElementRecord* nextNode = node->next(); + HTMLElementStack::ElementRecord* 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 @@ -1514,8 +1581,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; } @@ -1523,10 +1590,10 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken& token) if (node == formattingElementRecord) break; // 9.7 - RefPtr<HTMLStackItem> newItem = m_tree.createElementFromSavedToken(&node->stackItem()); + RefPtr<HTMLStackItem> newItem = m_tree.createElementFromSavedToken(node->stackItem().get()); - HTMLFormattingElementList::Entry* nodeEntry = m_tree.activeFormattingElements().find(&node->element()); - nodeEntry->replaceElement(newItem.copyRef()); + HTMLFormattingElementList::Entry* nodeEntry = m_tree.activeFormattingElements()->find(node->element()); + nodeEntry->replaceElement(newItem); node->replaceElement(newItem.release()); // 9.8 @@ -1538,18 +1605,18 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken& token) lastNode = node; } // 10. - m_tree.insertAlreadyParsedChild(commonAncestor.get(), *lastNode); + m_tree.insertAlreadyParsedChild(*commonAncestor, *lastNode); // 11. - RefPtr<HTMLStackItem> newItem = m_tree.createElementFromSavedToken(&formattingElementRecord->stackItem()); + RefPtr<HTMLStackItem> newItem = m_tree.createElementFromSavedToken(formattingElementRecord->stackItem().get()); // 12. m_tree.takeAllChildren(*newItem, *furthestBlock); // 13. m_tree.reparent(*furthestBlock, *newItem); // 14. - m_tree.activeFormattingElements().swapTo(formattingElement, newItem, bookmark); + m_tree.activeFormattingElements()->swapTo(formattingElement, newItem, bookmark); // 15. - m_tree.openElements().remove(formattingElement); - m_tree.openElements().insertAbove(newItem, furthestBlock); + m_tree.openElements()->remove(formattingElement); + m_tree.openElements()->insertAbove(newItem, furthestBlock); } } @@ -1557,9 +1624,10 @@ void HTMLTreeBuilder::resetInsertionModeAppropriately() { // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#reset-the-insertion-mode-appropriately bool last = false; - for (auto* record = &m_tree.openElements().topRecord(); ; record = record->next()) { - HTMLStackItem* item = &record->stackItem(); - if (&item->node() == &m_tree.openElements().rootNode()) { + HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord(); + while (1) { + RefPtr<HTMLStackItem> item = nodeRecord->stackItem(); + if (item->node() == m_tree.openElements()->rootNode()) { last = true; #if ENABLE(TEMPLATE_ELEMENT) bool shouldCreateItem = isParsingFragment(); @@ -1568,193 +1636,167 @@ void HTMLTreeBuilder::resetInsertionModeAppropriately() bool shouldCreateItem = true; #endif if (shouldCreateItem) - item = &m_fragmentContext.contextElementStackItem(); + item = HTMLStackItem::create(m_fragmentContext.contextElement(), HTMLStackItem::ItemForContextElement); } - #if ENABLE(TEMPLATE_ELEMENT) - if (item->hasTagName(templateTag)) { - m_insertionMode = m_templateInsertionModes.last(); - return; - } + if (item->hasTagName(templateTag)) + return setInsertionMode(m_templateInsertionModes.last()); #endif if (item->hasTagName(selectTag)) { #if ENABLE(TEMPLATE_ELEMENT) if (!last) { - 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; - } + while (item->node() != m_tree.openElements()->rootNode() && !item->hasTagName(templateTag)) { + nodeRecord = nodeRecord->next(); + item = nodeRecord->stackItem(); + if (isHTMLTableElement(item->node())) + return setInsertionMode(InsertionMode::InSelectInTable); } } #endif - 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; - } + 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); if (item->hasTagName(colgroupTag)) { - m_insertionMode = InsertionMode::InColumnGroup; - return; - } - if (is<HTMLTableElement>(item->node())) { - m_insertionMode = InsertionMode::InTable; - return; + return setInsertionMode(InsertionMode::InColumnGroup); } + 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()) { - m_insertionMode = InsertionMode::InHead; - return; - } + if (!m_fragmentContext.fragment() || m_fragmentContext.contextElement() != item->node()) + return setInsertionMode(InsertionMode::InHead); #endif - m_insertionMode = InsertionMode::InBody; - return; - } - if (item->hasTagName(bodyTag)) { - m_insertionMode = InsertionMode::InBody; - return; + return setInsertionMode(InsertionMode::InBody); } + if (item->hasTagName(bodyTag)) + return setInsertionMode(InsertionMode::InBody); if (item->hasTagName(framesetTag)) { - m_insertionMode = InsertionMode::InFrameset; - return; + return setInsertionMode(InsertionMode::InFrameset); } if (item->hasTagName(htmlTag)) { - if (m_tree.headStackItem()) { - m_insertionMode = InsertionMode::AfterHead; - return; - } + if (m_tree.headStackItem()) + return setInsertionMode(InsertionMode::AfterHead); ASSERT(isParsingFragment()); - m_insertionMode = InsertionMode::BeforeHead; - return; + return setInsertionMode(InsertionMode::BeforeHead); } if (last) { ASSERT(isParsingFragment()); - m_insertionMode = InsertionMode::InBody; - return; + return setInsertionMode(InsertionMode::InBody); } + 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(); - m_insertionMode = InsertionMode::InTable; + m_tree.openElements()->popUntilTableBodyScopeMarker(); + m_tree.openElements()->pop(); + setInsertionMode(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()); + m_tree.openElements()->popUntilTableBodyScopeMarker(); + ASSERT(isTableBodyContextTag(m_tree.currentStackItem()->localName())); + processFakeEndTag(m_tree.currentStackItem()->localName()); processEndTag(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); } -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(m_insertionMode == InsertionMode::InTableBody); + ASSERT(insertionMode() == InsertionMode::InTableBody); processEndTag(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(m_insertionMode == InsertionMode::InTableBody); + ASSERT(insertionMode() == InsertionMode::InTableBody); processEndTag(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); } -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(); - m_insertionMode = InsertionMode::InRow; + m_tree.openElements()->popUntilPopped(token->name()); + m_tree.activeFormattingElements()->clearToLastMarker(); + setInsertionMode(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 (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()); + ASSERT(isTableBodyContextTag(token->name()) || m_tree.openElements()->inTableScope(templateTag) || isParsingFragment()); #else - ASSERT(isTableBodyContextTag(token.name()) || isParsingFragment()); + ASSERT(isTableBodyContextTag(token->name()) || isParsingFragment()); #endif parseError(token); return; @@ -1766,146 +1808,149 @@ void HTMLTreeBuilder::processEndTagForInCell(AtomicHTMLToken& token) processEndTagForInBody(token); } -void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken& token) +void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken* token) { - ASSERT(token.type() == HTMLToken::EndTag); - if (token.name() == bodyTag) { + ASSERT(token->type() == HTMLToken::EndTag); + if (token->name() == bodyTag) { processBodyEndTagForInBody(token); return; } - if (token.name() == htmlTag) { + if (token->name() == htmlTag) { AtomicHTMLToken endBody(HTMLToken::EndTag, bodyTag.localName()); - if (processBodyEndTagForInBody(endBody)) + 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 (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())) { + if (!node || !m_tree.openElements()->inScope(node.get())) { parseError(token); return; } m_tree.generateImpliedEndTags(); - if (&m_tree.currentNode() != node.get()) + if (m_tree.currentNode() != node.get()) parseError(token); - m_tree.openElements().remove(node.get()); + m_tree.openElements()->remove(node.get()); } 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())); + ASSERT(m_tree.openElements()->inScope(token->name())); processEndTag(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 (HTMLConstructionSite::isFormattingTag(token.name())) { + if (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) { + if (token->name() == templateTag) { processTemplateEndTag(token); return; } @@ -1915,58 +1960,58 @@ void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken& 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(); - m_insertionMode = InsertionMode::InTable; + // FIXME: parse error if (!m_tree.currentStackItem()->hasTagName(captionTag)) + m_tree.openElements()->popUntilPopped(captionTag.localName()); + m_tree.activeFormattingElements()->clearToLastMarker(); + setInsertionMode(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(); - m_insertionMode = InsertionMode::InTableBody; + m_tree.openElements()->popUntilTableRowScopeMarker(); + ASSERT(m_tree.currentStackItem()->hasTagName(trTag)); + m_tree.openElements()->pop(); + setInsertionMode(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; } @@ -1976,72 +2021,75 @@ void HTMLTreeBuilder::processEndTagForInTable(AtomicHTMLToken& token) processEndTagForInBody(token); } -void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token) +void HTMLTreeBuilder::processEndTag(AtomicHTMLToken* token) { - ASSERT(token.type() == HTMLToken::EndTag); - switch (m_insertionMode) { + ASSERT(token->type() == HTMLToken::EndTag); + switch (insertionMode()) { case InsertionMode::Initial: + ASSERT(insertionMode() == InsertionMode::Initial); defaultForInitial(); - ASSERT(m_insertionMode == InsertionMode::BeforeHTML); FALLTHROUGH; case InsertionMode::BeforeHTML: - if (token.name() != headTag && token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) { + ASSERT(insertionMode() == InsertionMode::BeforeHTML); + 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: - if (token.name() != headTag && token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) { + ASSERT(insertionMode() == InsertionMode::BeforeHead); + 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) { + if (token->name() == templateTag) { processTemplateEndTag(token); return; } #endif - if (token.name() == headTag) { - m_tree.openElements().popHTMLHeadElement(); - m_insertionMode = InsertionMode::AfterHead; + if (token->name() == headTag) { + m_tree.openElements()->popHTMLHeadElement(); + setInsertionMode(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: - if (token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) { + ASSERT(insertionMode() == InsertionMode::AfterHead); + 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); break; case InsertionMode::InTable: + ASSERT(insertionMode() == InsertionMode::InTable); processEndTagForInTable(token); break; case InsertionMode::InCaption: - if (token.name() == captionTag) { + ASSERT(insertionMode() == InsertionMode::InCaption); + if (token->name() == captionTag) { processCaptionEndTagForInCaption(); return; } - if (token.name() == tableTag) { + if (token->name() == tableTag) { parseError(token); if (!processCaptionEndTagForInCaption()) { ASSERT(isParsingFragment()); @@ -2050,29 +2098,30 @@ void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token) processEndTag(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); break; case InsertionMode::InColumnGroup: - if (token.name() == colgroupTag) { + ASSERT(insertionMode() == InsertionMode::InColumnGroup); + 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) { + if (token->name() == templateTag) { processTemplateEndTag(token); return; } @@ -2084,39 +2133,44 @@ void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token) processEndTag(token); break; case InsertionMode::InRow: + ASSERT(insertionMode() == InsertionMode::InRow); processEndTagForInRow(token); break; case InsertionMode::InCell: + ASSERT(insertionMode() == InsertionMode::InCell); processEndTagForInCell(token); break; case InsertionMode::InTableBody: + ASSERT(insertionMode() == InsertionMode::InTableBody); processEndTagForInTableBody(token); break; case InsertionMode::AfterBody: - if (token.name() == htmlTag) { + ASSERT(insertionMode() == InsertionMode::AfterBody); + if (token->name() == htmlTag) { if (isParsingFragment()) { parseError(token); return; } - m_insertionMode = InsertionMode::AfterAfterBody; + setInsertionMode(InsertionMode::AfterAfterBody); return; } FALLTHROUGH; case InsertionMode::AfterAfterBody: - ASSERT(m_insertionMode == InsertionMode::AfterBody || m_insertionMode == InsertionMode::AfterAfterBody); + ASSERT(insertionMode() == InsertionMode::AfterBody || insertionMode() == InsertionMode::AfterAfterBody); parseError(token); - m_insertionMode = InsertionMode::InBody; + setInsertionMode(InsertionMode::InBody); processEndTag(token); break; case InsertionMode::InHeadNoscript: - if (token.name() == noscriptTag) { - ASSERT(m_tree.currentStackItem().hasTagName(noscriptTag)); - m_tree.openElements().pop(); - ASSERT(m_tree.currentStackItem().hasTagName(headTag)); - m_insertionMode = InsertionMode::InHead; + 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); return; } - if (token.name() != brTag) { + if (token->name() != brTag) { parseError(token); return; } @@ -2124,105 +2178,110 @@ void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token) processToken(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(); - 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(); + 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); + } return; } - m_tree.openElements().pop(); - m_insertionMode = m_originalInsertionMode; + m_tree.openElements()->pop(); + setInsertionMode(m_originalInsertionMode); break; case InsertionMode::InFrameset: - if (token.name() == framesetTag) { + ASSERT(insertionMode() == InsertionMode::InFrameset); + if (token->name() == framesetTag) { bool ignoreFramesetForFragmentParsing = m_tree.currentIsRootNode(); #if ENABLE(TEMPLATE_ELEMENT) - ignoreFramesetForFragmentParsing = ignoreFramesetForFragmentParsing || m_tree.openElements().hasTemplateInHTMLScope(); + ignoreFramesetForFragmentParsing = ignoreFramesetForFragmentParsing || m_tree.openElements()->hasTemplateInHTMLScope(); #endif if (ignoreFramesetForFragmentParsing) { ASSERT(isParsingFragmentOrTemplateContents()); parseError(token); return; } - m_tree.openElements().pop(); - if (!isParsingFragment() && !m_tree.currentStackItem().hasTagName(framesetTag)) - m_insertionMode = InsertionMode::AfterFrameset; + m_tree.openElements()->pop(); + if (!isParsingFragment() && !m_tree.currentStackItem()->hasTagName(framesetTag)) + setInsertionMode(InsertionMode::AfterFrameset); return; } #if ENABLE(TEMPLATE_ELEMENT) - if (token.name() == templateTag) { + if (token->name() == templateTag) { processTemplateEndTag(token); return; } #endif break; case InsertionMode::AfterFrameset: - if (token.name() == htmlTag) { - m_insertionMode = InsertionMode::AfterAfterFrameset; + ASSERT(insertionMode() == InsertionMode::AfterFrameset); + if (token->name() == htmlTag) { + setInsertionMode(InsertionMode::AfterAfterFrameset); return; } FALLTHROUGH; case InsertionMode::AfterAfterFrameset: - ASSERT(m_insertionMode == InsertionMode::AfterFrameset || m_insertionMode == InsertionMode::AfterAfterFrameset); + ASSERT(insertionMode() == InsertionMode::AfterFrameset || insertionMode() == InsertionMode::AfterAfterFrameset); parseError(token); break; case InsertionMode::InSelectInTable: - if (token.name() == captionTag - || token.name() == tableTag - || isTableBodyContextTag(token.name()) - || token.name() == trTag - || isTableCellContextTag(token.name())) { + ASSERT(insertionMode() == InsertionMode::InSelectInTable); + 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(&endSelect); processEndTag(token); } return; } FALLTHROUGH; case InsertionMode::InSelect: - 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())) + 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())) processFakeEndTag(optionTag); - if (is<HTMLOptGroupElement>(m_tree.currentStackItem().node())) { - m_tree.openElements().pop(); + if (isHTMLOptGroupElement(m_tree.currentStackItem()->node())) { + m_tree.openElements()->pop(); return; } parseError(token); return; } - if (token.name() == optionTag) { - if (is<HTMLOptionElement>(m_tree.currentStackItem().node())) { - m_tree.openElements().pop(); + if (token->name() == optionTag) { + if (isHTMLOptionElement(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) { + if (token->name() == templateTag) { processTemplateEndTag(token); return; } @@ -2232,29 +2291,33 @@ void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token) defaultForInTableText(); processEndTag(token); break; -#if ENABLE(TEMPLATE_ELEMENT) case InsertionMode::TemplateContents: - if (token.name() == templateTag) { +#if ENABLE(TEMPLATE_ELEMENT) + if (token->name() == templateTag) { processTemplateEndTag(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(token); return; } if (m_insertionMode == InsertionMode::AfterBody) { - m_tree.insertCommentOnHTMLHtmlElement(&token); + m_tree.insertCommentOnHTMLHtmlElement(token); return; } if (m_insertionMode == InsertionMode::InTableText) { @@ -2262,19 +2325,18 @@ void HTMLTreeBuilder::processComment(AtomicHTMLToken& token) processComment(token); return; } - m_tree.insertComment(&token); + m_tree.insertComment(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) { @@ -2282,13 +2344,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, WTFMove(attributes)); + AtomicHTMLToken aStartToken(HTMLToken::StartTag, aTagLocalName, attributes); AtomicHTMLToken aEndToken(HTMLToken::EndTag, aTagLocalName); - processStartTag(aStartToken); + processStartTag(&aStartToken); m_tree.executeQueuedTasks(); m_tree.insertTextNode(string); - processEndTag(aEndToken); + processEndTag(&aEndToken); } // Locates the phone numbers in the string and deals with it @@ -2298,7 +2360,13 @@ void HTMLTreeBuilder::insertPhoneNumberLink(const String& string) // 4. Appends the rest of the string as a text node. void HTMLTreeBuilder::linkifyPhoneNumbers(const String& string) { - ASSERT(TelephoneNumberDetector::isSupported()); + static DDDFACacheRef phoneNumbersCache = DDDFACacheCreateFromFramework(); + if (!phoneNumbersCache) { + m_tree.insertTextNode(string); + return; + } + + static DDDFAScannerRef phoneNumbersScanner = DDDFAScannerCreateFromCache(phoneNumbersCache); // relativeStartPosition and relativeEndPosition are the endpoints of the phone number range, // relative to the scannerPosition @@ -2307,10 +2375,8 @@ 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 && TelephoneNumberDetector::find(&characters[scannerPosition], length - scannerPosition, &relativeStartPosition, &relativeEndPosition)) { + while ((scannerPosition < length) && DDDFAScannerFirstResultInUnicharArray(phoneNumbersScanner, &string.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 @@ -2336,11 +2402,12 @@ 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 ContainerNode& node) +static inline bool disallowTelephoneNumberParsing(const Node& node) { return node.isLink() + || node.nodeType() == Node::COMMENT_NODE || node.hasTagName(scriptTag) - || is<HTMLFormControlElement>(node) + || (node.isHTMLElement() && toHTMLElement(node).isFormControlElement()) || node.hasTagName(styleTag) || node.hasTagName(ttTag) || node.hasTagName(preTag) @@ -2349,14 +2416,15 @@ static inline bool disallowTelephoneNumberParsing(const ContainerNode& node) static inline bool shouldParseTelephoneNumbersInNode(const ContainerNode& node) { - for (const ContainerNode* ancestor = &node; ancestor; ancestor = ancestor->parentNode()) { - if (disallowTelephoneNumberParsing(*ancestor)) + const ContainerNode* currentNode = &node; + do { + if (currentNode->isElementNode() && disallowTelephoneNumberParsing(*currentNode)) return false; - } + currentNode = currentNode->parentNode(); + } while (currentNode); return true; } - -#endif // ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS) +#endif // PLATFORM(IOS) void HTMLTreeBuilder::processCharacterBuffer(ExternalCharacterTokenBuffer& buffer) { @@ -2379,68 +2447,77 @@ ReprocessBuffer: return; } - switch (m_insertionMode) { - case InsertionMode::Initial: + switch (insertionMode()) { + case InsertionMode::Initial: { + ASSERT(insertionMode() == InsertionMode::Initial); buffer.skipLeadingWhitespace(); if (buffer.isEmpty()) return; defaultForInitial(); - ASSERT(m_insertionMode == InsertionMode::BeforeHTML); FALLTHROUGH; - case InsertionMode::BeforeHTML: + } + case InsertionMode::BeforeHTML: { + ASSERT(insertionMode() == InsertionMode::BeforeHTML); buffer.skipLeadingWhitespace(); if (buffer.isEmpty()) return; defaultForBeforeHTML(); - ASSERT(m_insertionMode == InsertionMode::BeforeHead); FALLTHROUGH; - case InsertionMode::BeforeHead: + } + case InsertionMode::BeforeHead: { + ASSERT(insertionMode() == 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: -#if ENABLE(TEMPLATE_ELEMENT) 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: + case InsertionMode::InRow: { + ASSERT(insertionMode() == InsertionMode::InTable || insertionMode() == InsertionMode::InTableBody || insertionMode() == InsertionMode::InRow); ASSERT(m_pendingTableCharacters.isEmpty()); - 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)) { - + 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))) { m_originalInsertionMode = m_insertionMode; - m_insertionMode = InsertionMode::InTableText; + setInsertionMode(InsertionMode::InTableText); // Note that we fall through to the InsertionMode::InTableText case below. } else { HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree); @@ -2448,10 +2525,13 @@ 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); @@ -2467,14 +2547,20 @@ ReprocessBuffer: goto ReprocessBuffer; } case InsertionMode::AfterBody: - case InsertionMode::AfterAfterBody: + case InsertionMode::AfterAfterBody: { + ASSERT(insertionMode() == InsertionMode::AfterBody || insertionMode() == InsertionMode::AfterAfterBody); // FIXME: parse error - m_insertionMode = InsertionMode::InBody; + setInsertionMode(InsertionMode::InBody); goto ReprocessBuffer; - case InsertionMode::Text: + break; + } + case InsertionMode::Text: { + ASSERT(insertionMode() == 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); @@ -2482,9 +2568,11 @@ 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); @@ -2493,9 +2581,11 @@ ReprocessBuffer: break; } case InsertionMode::InSelectInTable: - case InsertionMode::InSelect: + case InsertionMode::InSelect: { + ASSERT(insertionMode() == InsertionMode::InSelect || insertionMode() == InsertionMode::InSelectInTable); m_tree.insertTextNode(buffer.takeRemaining()); break; + } case InsertionMode::AfterAfterFrameset: { String leadingWhitespace = buffer.takeRemainingWhitespace(); if (!leadingWhitespace.isEmpty()) { @@ -2513,63 +2603,72 @@ void HTMLTreeBuilder::processCharacterBufferForInBody(ExternalCharacterTokenBuff { m_tree.reconstructTheActiveFormattingElements(); String characters = buffer.takeRemaining(); -#if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS) - if (!isParsingFragment() && m_tree.isTelephoneNumberParsingEnabled() && shouldParseTelephoneNumbersInNode(m_tree.currentNode()) && TelephoneNumberDetector::isSupported()) +#if PLATFORM(IOS) + if (!isParsingFragment() && m_tree.isTelephoneNumberParsingEnabled() && shouldParseTelephoneNumbersInNode(*m_tree.currentNode()) && DataDetectorsCoreLibrary()) 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 (m_insertionMode) { + ASSERT(token->type() == HTMLToken::EndOfFile); + switch (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 (!m_templateInsertionModes.isEmpty()) if (processEndOfFileForInTemplateContents(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); return; case InsertionMode::AfterFrameset: case InsertionMode::AfterAfterFrameset: + ASSERT(insertionMode() == InsertionMode::AfterFrameset || insertionMode() == InsertionMode::AfterAfterFrameset); break; case InsertionMode::InColumnGroup: if (m_tree.currentIsRootNode()) { @@ -2577,9 +2676,9 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken& token) return; // FIXME: Should we break here instead of returning? } #if ENABLE(TEMPLATE_ELEMENT) - ASSERT(m_tree.currentNode().hasTagName(colgroupTag) || m_tree.currentNode().hasTagName(templateTag)); + ASSERT(m_tree.currentNode()->hasTagName(colgroupTag) || m_tree.currentNode()->hasTagName(templateTag)); #else - ASSERT(m_tree.currentNode().hasTagName(colgroupTag)); + ASSERT(m_tree.currentNode()->hasTagName(colgroupTag)); #endif processColgroupEndTagForInColumnGroup(); FALLTHROUGH; @@ -2588,14 +2687,14 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken& token) case InsertionMode::InTableBody: case InsertionMode::InSelectInTable: case InsertionMode::InSelect: - 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()) + 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()) parseError(token); + #if ENABLE(TEMPLATE_ELEMENT) - if (!m_templateInsertionModes.isEmpty()) { + if (!m_templateInsertionModes.isEmpty()) if (processEndOfFileForInTemplateContents(token)) return; - } #endif break; case InsertionMode::InTableText: @@ -2604,21 +2703,24 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken& 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); - m_insertionMode = m_originalInsertionMode; + setInsertionMode(m_originalInsertionMode); processEndOfFile(token); return; -#if ENABLE(TEMPLATE_ELEMENT) case InsertionMode::TemplateContents: +#if ENABLE(TEMPLATE_ELEMENT) if (processEndOfFileForInTemplateContents(token)) return; break; +#else + ASSERT_NOT_REACHED(); #endif } - m_tree.openElements().popAll(); + ASSERT(m_tree.currentNode()); + m_tree.openElements()->popAll(); } void HTMLTreeBuilder::defaultForInitial() @@ -2626,38 +2728,38 @@ void HTMLTreeBuilder::defaultForInitial() notImplemented(); m_tree.setDefaultCompatibilityMode(); // FIXME: parse error - m_insertionMode = InsertionMode::BeforeHTML; + setInsertionMode(InsertionMode::BeforeHTML); } void HTMLTreeBuilder::defaultForBeforeHTML() { AtomicHTMLToken startHTML(HTMLToken::StartTag, htmlTag.localName()); m_tree.insertHTMLHtmlStartTagBeforeHTML(&startHTML); - m_insertionMode = InsertionMode::BeforeHead; + setInsertionMode(InsertionMode::BeforeHead); } void HTMLTreeBuilder::defaultForBeforeHead() { AtomicHTMLToken startHead(HTMLToken::StartTag, headTag.localName()); - processStartTag(startHead); + processStartTag(&startHead); } void HTMLTreeBuilder::defaultForInHead() { AtomicHTMLToken endHead(HTMLToken::EndTag, headTag.localName()); - processEndTag(endHead); + processEndTag(&endHead); } void HTMLTreeBuilder::defaultForInHeadNoscript() { AtomicHTMLToken endNoscript(HTMLToken::EndTag, noscriptTag.localName()); - processEndTag(endNoscript); + processEndTag(&endNoscript); } void HTMLTreeBuilder::defaultForAfterHead() { AtomicHTMLToken startBody(HTMLToken::StartTag, bodyTag.localName()); - processStartTag(startBody); + processStartTag(&startBody); m_framesetOk = true; } @@ -2671,149 +2773,135 @@ void HTMLTreeBuilder::defaultForInTableText() m_tree.reconstructTheActiveFormattingElements(); m_tree.insertTextNode(characters, NotAllWhitespace); m_framesetOk = false; - m_insertionMode = m_originalInsertionMode; + setInsertionMode(m_originalInsertionMode); return; } m_tree.insertTextNode(characters); - m_insertionMode = m_originalInsertionMode; + setInsertionMode(m_originalInsertionMode); } -bool HTMLTreeBuilder::processStartTagForInHead(AtomicHTMLToken& token) +bool HTMLTreeBuilder::processStartTagForInHead(AtomicHTMLToken* token) { - ASSERT(token.type() == HTMLToken::StartTag); - if (token.name() == htmlTag) { + ASSERT(token->type() == HTMLToken::StartTag); + if (token->name() == htmlTag) { processHtmlStartTagForInBody(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(token); // Note: The custom processing for the <meta> tag is done in HTMLMetaElement::process(). return true; } - if (token.name() == titleTag) { + if (token->name() == titleTag) { processGenericRCDATAStartTag(token); return true; } - if (token.name() == noscriptTag) { + if (token->name() == noscriptTag) { if (m_options.scriptEnabled) { processGenericRawTextStartTag(token); return true; } - m_tree.insertHTMLElement(&token); - m_insertionMode = InsertionMode::InHeadNoscript; + m_tree.insertHTMLElement(token); + setInsertionMode(InsertionMode::InHeadNoscript); return true; } - if (token.name() == noframesTag || token.name() == styleTag) { + if (token->name() == noframesTag || token->name() == styleTag) { processGenericRawTextStartTag(token); return true; } - if (token.name() == scriptTag) { + if (token->name() == scriptTag) { processScriptStartTag(token); - if (m_options.usePreHTML5ParserQuirks && token.selfClosing()) + if (m_options.usePreHTML5ParserQuirks && token->selfClosing()) processFakeEndTag(scriptTag); return true; } #if ENABLE(TEMPLATE_ELEMENT) - if (token.name() == templateTag) { + if (token->name() == templateTag) { processTemplateStartTag(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); - m_parser.tokenizer().setRCDATAState(); + ASSERT(token->type() == HTMLToken::StartTag); + m_tree.insertHTMLElement(token); + if (m_parser.tokenizer()) + m_parser.tokenizer()->setState(HTMLTokenizer::RCDATAState); m_originalInsertionMode = m_insertionMode; - m_insertionMode = InsertionMode::Text; + setInsertionMode(InsertionMode::Text); } -void HTMLTreeBuilder::processGenericRawTextStartTag(AtomicHTMLToken& token) +void HTMLTreeBuilder::processGenericRawTextStartTag(AtomicHTMLToken* token) { - ASSERT(token.type() == HTMLToken::StartTag); - m_tree.insertHTMLElement(&token); - m_parser.tokenizer().setRAWTEXTState(); + ASSERT(token->type() == HTMLToken::StartTag); + m_tree.insertHTMLElement(token); + if (m_parser.tokenizer()) + m_parser.tokenizer()->setState(HTMLTokenizer::RAWTEXTState); m_originalInsertionMode = m_insertionMode; - m_insertionMode = InsertionMode::Text; + setInsertionMode(InsertionMode::Text); } -void HTMLTreeBuilder::processScriptStartTag(AtomicHTMLToken& token) +void HTMLTreeBuilder::processScriptStartTag(AtomicHTMLToken* token) { - ASSERT(token.type() == HTMLToken::StartTag); - m_tree.insertScriptElement(&token); - m_parser.tokenizer().setScriptDataState(); + ASSERT(token->type() == HTMLToken::StartTag); + m_tree.insertScriptElement(token); + if (m_parser.tokenizer()) + m_parser.tokenizer()->setState(HTMLTokenizer::ScriptDataState); m_originalInsertionMode = m_insertionMode; TextPosition position = m_parser.textPosition(); m_scriptToProcessStartPosition = position; - 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(); + setInsertionMode(InsertionMode::Text); } // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#tree-construction -bool HTMLTreeBuilder::shouldProcessTokenInForeignContent(AtomicHTMLToken& token) +bool HTMLTreeBuilder::shouldProcessTokenInForeignContent(AtomicHTMLToken* token) { if (m_tree.isEmpty()) return false; - HTMLStackItem& adjustedCurrentNode = adjustedCurrentStackItem(); - if (isInHTMLNamespace(adjustedCurrentNode)) + HTMLStackItem* item = m_tree.currentStackItem(); + if (item->isInHTMLNamespace()) return false; - if (HTMLElementStack::isMathMLTextIntegrationPoint(adjustedCurrentNode)) { - if (token.type() == HTMLToken::StartTag - && token.name() != MathMLNames::mglyphTag - && token.name() != MathMLNames::malignmarkTag) + if (HTMLElementStack::isMathMLTextIntegrationPoint(item)) { + 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 (adjustedCurrentNode.hasTagName(MathMLNames::annotation_xmlTag) - && token.type() == HTMLToken::StartTag - && token.name() == SVGNames::svgTag) + if (item->hasTagName(MathMLNames::annotation_xmlTag) + && token->type() == HTMLToken::StartTag + && token->name() == SVGNames::svgTag) return false; - if (HTMLElementStack::isHTMLIntegrationPoint(adjustedCurrentNode)) { - if (token.type() == HTMLToken::StartTag) + if (HTMLElementStack::isHTMLIntegrationPoint(item)) { + 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; } -static bool hasAttribute(AtomicHTMLToken& token, const QualifiedName& name) +void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken* token) { - return findAttribute(token.attributes(), name); -} - -void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken& token) -{ - HTMLStackItem& adjustedCurrentNode = adjustedCurrentStackItem(); - - switch (token.type()) { + switch (token->type()) { case HTMLToken::Uninitialized: ASSERT_NOT_REACHED(); break; @@ -2821,52 +2909,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 && (hasAttribute(token, colorAttr) || hasAttribute(token, faceAttr) || hasAttribute(token, 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 && (token->getAttributeItem(colorAttr) || token->getAttributeItem(faceAttr) || token->getAttributeItem(sizeAttr)))) { parseError(token); - m_tree.openElements().popUntilForeignContentScopeMarker(); + m_tree.openElements()->popUntilForeignContentScopeMarker(); processStartTag(token); return; } - const AtomicString& currentNamespace = adjustedCurrentNode.namespaceURI(); + const AtomicString& currentNamespace = m_tree.currentStackItem()->namespaceURI(); if (currentNamespace == MathMLNames::mathmlNamespaceURI) adjustMathMLAttributes(token); if (currentNamespace == SVGNames::svgNamespaceURI) { @@ -2874,32 +2962,32 @@ void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken& token) adjustSVGAttributes(token); } adjustForeignAttributes(token); - m_tree.insertForeignElement(&token, currentNamespace); + m_tree.insertForeignElement(token, currentNamespace); break; } case HTMLToken::EndTag: { - if (adjustedCurrentNode.namespaceURI() == SVGNames::svgNamespaceURI) + if (m_tree.currentStackItem()->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 = m_tree.currentElement(); + m_tree.openElements()->pop(); return; } - if (!isInHTMLNamespace(m_tree.currentStackItem())) { + if (!m_tree.currentStackItem()->isInHTMLNamespace()) { // FIXME: This code just wants an Element* iterator, instead of an ElementRecord* - auto* nodeRecord = &m_tree.openElements().topRecord(); - if (nodeRecord->stackItem().localName() != token.name()) + HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord(); + if (!nodeRecord->stackItem()->hasLocalName(token->name())) parseError(token); while (1) { - if (nodeRecord->stackItem().localName() == token.name()) { - m_tree.openElements().popUntilPopped(&nodeRecord->element()); + if (nodeRecord->stackItem()->hasLocalName(token->name())) { + m_tree.openElements()->popUntilPopped(nodeRecord->element()); return; } nodeRecord = nodeRecord->next(); - if (isInHTMLNamespace(nodeRecord->stackItem())) + if (nodeRecord->stackItem()->isInHTMLNamespace()) break; } } @@ -2908,10 +2996,10 @@ void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken& token) break; } case HTMLToken::Comment: - m_tree.insertComment(&token); + m_tree.insertComment(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; @@ -2925,8 +3013,6 @@ void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken& token) void HTMLTreeBuilder::finished() { - ASSERT(!m_destroyed); - if (isParsingFragment()) return; @@ -2934,11 +3020,12 @@ void HTMLTreeBuilder::finished() 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. } -inline void HTMLTreeBuilder::parseError(AtomicHTMLToken&) +void HTMLTreeBuilder::parseError(AtomicHTMLToken*) { } |