summaryrefslogtreecommitdiff
path: root/Source/WebCore/html/parser
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/html/parser')
-rw-r--r--Source/WebCore/html/parser/AtomicHTMLToken.h347
-rw-r--r--Source/WebCore/html/parser/CSSPreloadScanner.cpp23
-rw-r--r--Source/WebCore/html/parser/CSSPreloadScanner.h7
-rw-r--r--Source/WebCore/html/parser/HTMLConstructionSite.cpp568
-rw-r--r--Source/WebCore/html/parser/HTMLConstructionSite.h113
-rw-r--r--Source/WebCore/html/parser/HTMLDocumentParser.cpp358
-rw-r--r--Source/WebCore/html/parser/HTMLDocumentParser.h140
-rw-r--r--Source/WebCore/html/parser/HTMLElementStack.cpp381
-rw-r--r--Source/WebCore/html/parser/HTMLElementStack.h102
-rw-r--r--Source/WebCore/html/parser/HTMLEntityParser.cpp40
-rw-r--r--Source/WebCore/html/parser/HTMLEntityParser.h7
-rw-r--r--Source/WebCore/html/parser/HTMLEntitySearch.h7
-rw-r--r--Source/WebCore/html/parser/HTMLEntityTable.h7
-rw-r--r--Source/WebCore/html/parser/HTMLFormattingElementList.cpp73
-rw-r--r--Source/WebCore/html/parser/HTMLFormattingElementList.h53
-rw-r--r--Source/WebCore/html/parser/HTMLInputStream.h22
-rw-r--r--Source/WebCore/html/parser/HTMLMetaCharsetParser.cpp95
-rw-r--r--Source/WebCore/html/parser/HTMLMetaCharsetParser.h35
-rw-r--r--Source/WebCore/html/parser/HTMLParserIdioms.cpp450
-rw-r--r--Source/WebCore/html/parser/HTMLParserIdioms.h93
-rw-r--r--Source/WebCore/html/parser/HTMLParserOptions.cpp7
-rw-r--r--Source/WebCore/html/parser/HTMLParserOptions.h7
-rw-r--r--Source/WebCore/html/parser/HTMLParserScheduler.cpp27
-rw-r--r--Source/WebCore/html/parser/HTMLParserScheduler.h58
-rw-r--r--Source/WebCore/html/parser/HTMLPreloadScanner.cpp295
-rw-r--r--Source/WebCore/html/parser/HTMLPreloadScanner.h82
-rw-r--r--Source/WebCore/html/parser/HTMLResourcePreloader.cpp50
-rw-r--r--Source/WebCore/html/parser/HTMLResourcePreloader.h33
-rw-r--r--Source/WebCore/html/parser/HTMLScriptRunner.cpp208
-rw-r--r--Source/WebCore/html/parser/HTMLScriptRunner.h31
-rw-r--r--Source/WebCore/html/parser/HTMLScriptRunnerHost.h20
-rw-r--r--Source/WebCore/html/parser/HTMLSourceTracker.cpp48
-rw-r--r--Source/WebCore/html/parser/HTMLSourceTracker.h27
-rw-r--r--Source/WebCore/html/parser/HTMLSrcsetParser.cpp276
-rw-r--r--Source/WebCore/html/parser/HTMLSrcsetParser.h109
-rw-r--r--Source/WebCore/html/parser/HTMLStackItem.h303
-rw-r--r--Source/WebCore/html/parser/HTMLToken.h679
-rw-r--r--Source/WebCore/html/parser/HTMLTokenizer.cpp2235
-rw-r--r--Source/WebCore/html/parser/HTMLTokenizer.h339
-rw-r--r--Source/WebCore/html/parser/HTMLTreeBuilder.cpp2499
-rw-r--r--Source/WebCore/html/parser/HTMLTreeBuilder.h237
-rw-r--r--Source/WebCore/html/parser/HTMLViewSourceParser.cpp90
-rw-r--r--Source/WebCore/html/parser/HTMLViewSourceParser.h79
-rw-r--r--Source/WebCore/html/parser/InputStreamPreprocessor.h92
-rw-r--r--Source/WebCore/html/parser/NestingLevelIncrementer.h7
-rw-r--r--Source/WebCore/html/parser/ParsingUtilities.h83
-rw-r--r--Source/WebCore/html/parser/TextDocumentParser.cpp23
-rw-r--r--Source/WebCore/html/parser/TextDocumentParser.h22
-rw-r--r--Source/WebCore/html/parser/TextViewSourceParser.cpp43
-rw-r--r--Source/WebCore/html/parser/TextViewSourceParser.h47
-rw-r--r--Source/WebCore/html/parser/XSSAuditor.cpp374
-rw-r--r--Source/WebCore/html/parser/XSSAuditor.h29
-rw-r--r--Source/WebCore/html/parser/XSSAuditorDelegate.cpp45
-rw-r--r--Source/WebCore/html/parser/XSSAuditorDelegate.h27
54 files changed, 5701 insertions, 5751 deletions
diff --git a/Source/WebCore/html/parser/AtomicHTMLToken.h b/Source/WebCore/html/parser/AtomicHTMLToken.h
index 909487c54..d09afbc1b 100644
--- a/Source/WebCore/html/parser/AtomicHTMLToken.h
+++ b/Source/WebCore/html/parser/AtomicHTMLToken.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2013 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2015 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,221 +24,233 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef AtomicHTMLToken_h
-#define AtomicHTMLToken_h
+#pragma once
-#include "Attribute.h"
#include "HTMLToken.h"
-#include <wtf/RefCounted.h>
-#include <wtf/RefPtr.h>
namespace WebCore {
class AtomicHTMLToken {
- WTF_MAKE_NONCOPYABLE(AtomicHTMLToken);
public:
+ explicit AtomicHTMLToken(HTMLToken&);
+ AtomicHTMLToken(HTMLToken::Type, const AtomicString& name, Vector<Attribute>&& = { }); // Only StartTag or EndTag.
- bool forceQuirks() const
- {
- ASSERT(m_type == HTMLToken::DOCTYPE);
- return m_doctypeData->m_forceQuirks;
- }
-
- HTMLToken::Type type() const { return m_type; }
-
- const AtomicString& name() const
- {
- ASSERT(usesName());
- return m_name;
- }
-
- void setName(const AtomicString& name)
- {
- ASSERT(usesName());
- m_name = name;
- }
+ AtomicHTMLToken(const AtomicHTMLToken&) = delete;
+ AtomicHTMLToken(AtomicHTMLToken&&) = default;
- bool selfClosing() const
- {
- ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag);
- return m_selfClosing;
- }
+ HTMLToken::Type type() const;
- Attribute* getAttributeItem(const QualifiedName& attributeName)
- {
- ASSERT(usesAttributes());
- return findAttributeInVector(m_attributes, attributeName);
- }
+ // StartTag, EndTag, DOCTYPE.
- Vector<Attribute>& attributes()
- {
- ASSERT(usesAttributes());
- return m_attributes;
- }
+ void setName(const AtomicString&);
- const Vector<Attribute>& attributes() const
- {
- ASSERT(usesAttributes());
- return m_attributes;
- }
+ const AtomicString& name() const;
- const UChar* characters() const
- {
- ASSERT(m_type == HTMLToken::Character);
- return m_externalCharacters;
- }
+ // DOCTYPE.
- size_t charactersLength() const
- {
- ASSERT(m_type == HTMLToken::Character);
- return m_externalCharactersLength;
- }
+ bool forceQuirks() const;
+ String publicIdentifier() const;
+ String systemIdentifier() const;
- bool isAll8BitData() const
- {
- return m_isAll8BitData;
- }
+ // StartTag, EndTag.
- const String& comment() const
- {
- ASSERT(m_type == HTMLToken::Comment);
- return m_data;
- }
+ Vector<Attribute>& attributes();
- // FIXME: Distinguish between a missing public identifer and an empty one.
- Vector<UChar>& publicIdentifier() const
- {
- ASSERT(m_type == HTMLToken::DOCTYPE);
- return m_doctypeData->m_publicIdentifier;
- }
+ bool selfClosing() const;
+ const Vector<Attribute>& attributes() const;
- // FIXME: Distinguish between a missing system identifer and an empty one.
- Vector<UChar>& systemIdentifier() const
- {
- ASSERT(m_type == HTMLToken::DOCTYPE);
- return m_doctypeData->m_systemIdentifier;
- }
+ // Characters
- explicit AtomicHTMLToken(HTMLToken& token)
- : m_type(token.type())
- {
- switch (m_type) {
- case HTMLToken::Uninitialized:
- ASSERT_NOT_REACHED();
- break;
- case HTMLToken::DOCTYPE:
- m_name = AtomicString(token.name());
- m_doctypeData = token.releaseDoctypeData();
- break;
- case HTMLToken::EndOfFile:
- break;
- case HTMLToken::StartTag:
- case HTMLToken::EndTag: {
- m_selfClosing = token.selfClosing();
- m_name = AtomicString(token.name());
- initializeAttributes(token.attributes());
- break;
- }
- case HTMLToken::Comment:
- if (token.isAll8BitData())
- m_data = String::make8BitFrom16BitSource(token.comment());
- else
- m_data = String(token.comment());
- break;
- case HTMLToken::Character:
- m_externalCharacters = token.characters().data();
- m_externalCharactersLength = token.characters().size();
- m_isAll8BitData = token.isAll8BitData();
- break;
- }
- }
+ const UChar* characters() const;
+ unsigned charactersLength() const;
+ bool charactersIsAll8BitData() const;
- explicit AtomicHTMLToken(HTMLToken::Type type)
- : m_type(type)
- , m_externalCharacters(0)
- , m_externalCharactersLength(0)
- , m_isAll8BitData(false)
- , m_selfClosing(false)
- {
- }
+ // Comment
- AtomicHTMLToken(HTMLToken::Type type, const AtomicString& name, const Vector<Attribute>& attributes = Vector<Attribute>())
- : m_type(type)
- , m_name(name)
- , m_externalCharacters(0)
- , m_externalCharactersLength(0)
- , m_isAll8BitData(false)
- , m_selfClosing(false)
- , m_attributes(attributes)
- {
- ASSERT(usesName());
- }
+ const String& comment() const;
private:
HTMLToken::Type m_type;
void initializeAttributes(const HTMLToken::AttributeList& attributes);
- QualifiedName nameForAttribute(const HTMLToken::Attribute&) const;
- bool usesName() const;
+ AtomicString m_name; // StartTag, EndTag, DOCTYPE.
- bool usesAttributes() const;
+ String m_data; // Comment
- // "name" for DOCTYPE, StartTag, and EndTag
- AtomicString m_name;
+ // We don't want to copy the the characters out of the HTMLToken, so we keep a pointer to its buffer instead.
+ // This buffer is owned by the HTMLToken and causes a lifetime dependence between these objects.
+ // FIXME: Add a mechanism for "internalizing" the characters when the HTMLToken is destroyed.
+ const UChar* m_externalCharacters; // Character
+ unsigned m_externalCharactersLength; // Character
+ bool m_externalCharactersIsAll8BitData; // Character
- // "data" for Comment
- String m_data;
+ std::unique_ptr<DoctypeData> m_doctypeData; // DOCTYPE.
- // "characters" for Character
- //
- // We don't want to copy the the characters out of the Token, so we
- // keep a pointer to its buffer instead. This buffer is owned by the
- // Token and causes a lifetime dependence between these objects.
- //
- // FIXME: Add a mechanism for "internalizing" the characters when the
- // HTMLToken is destructed.
- const UChar* m_externalCharacters;
- size_t m_externalCharactersLength;
- bool m_isAll8BitData;
+ bool m_selfClosing; // StartTag, EndTag.
+ Vector<Attribute> m_attributes; // StartTag, EndTag.
+};
- // For DOCTYPE
- std::unique_ptr<DoctypeData> m_doctypeData;
+const Attribute* findAttribute(const Vector<Attribute>&, const QualifiedName&);
+bool hasAttribute(const Vector<Attribute>&, const AtomicString& localName);
- // For StartTag and EndTag
- bool m_selfClosing;
+inline HTMLToken::Type AtomicHTMLToken::type() const
+{
+ return m_type;
+}
- Vector<Attribute> m_attributes;
-};
+inline const AtomicString& AtomicHTMLToken::name() const
+{
+ ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag || m_type == HTMLToken::DOCTYPE);
+ return m_name;
+}
+
+inline void AtomicHTMLToken::setName(const AtomicString& name)
+{
+ ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag || m_type == HTMLToken::DOCTYPE);
+ m_name = name;
+}
+
+inline bool AtomicHTMLToken::selfClosing() const
+{
+ ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag);
+ return m_selfClosing;
+}
+
+inline Vector<Attribute>& AtomicHTMLToken::attributes()
+{
+ ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag);
+ return m_attributes;
+}
+
+inline const Vector<Attribute>& AtomicHTMLToken::attributes() const
+{
+ ASSERT(m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag);
+ return m_attributes;
+}
+
+inline const UChar* AtomicHTMLToken::characters() const
+{
+ ASSERT(m_type == HTMLToken::Character);
+ return m_externalCharacters;
+}
+
+inline unsigned AtomicHTMLToken::charactersLength() const
+{
+ ASSERT(m_type == HTMLToken::Character);
+ return m_externalCharactersLength;
+}
+
+inline bool AtomicHTMLToken::charactersIsAll8BitData() const
+{
+ return m_externalCharactersIsAll8BitData;
+}
+
+inline const String& AtomicHTMLToken::comment() const
+{
+ ASSERT(m_type == HTMLToken::Comment);
+ return m_data;
+}
+
+inline bool AtomicHTMLToken::forceQuirks() const
+{
+ ASSERT(m_type == HTMLToken::DOCTYPE);
+ return m_doctypeData->forceQuirks;
+}
+
+inline String AtomicHTMLToken::publicIdentifier() const
+{
+ ASSERT(m_type == HTMLToken::DOCTYPE);
+ if (!m_doctypeData->hasPublicIdentifier)
+ return String();
+ return StringImpl::create8BitIfPossible(m_doctypeData->publicIdentifier);
+}
+
+inline String AtomicHTMLToken::systemIdentifier() const
+{
+ if (!m_doctypeData->hasSystemIdentifier)
+ return String();
+ return StringImpl::create8BitIfPossible(m_doctypeData->systemIdentifier);
+}
+
+inline const Attribute* findAttribute(const Vector<Attribute>& attributes, const QualifiedName& name)
+{
+ for (auto& attribute : attributes) {
+ if (attribute.name().matches(name))
+ return &attribute;
+ }
+ return nullptr;
+}
+
+inline bool hasAttribute(const Vector<Attribute>& attributes, const AtomicString& localName)
+{
+ for (auto& attribute : attributes) {
+ if (attribute.localName() == localName)
+ return true;
+ }
+ return false;
+}
inline void AtomicHTMLToken::initializeAttributes(const HTMLToken::AttributeList& attributes)
{
- size_t size = attributes.size();
+ unsigned size = attributes.size();
if (!size)
return;
- m_attributes.clear();
m_attributes.reserveInitialCapacity(size);
- for (size_t i = 0; i < size; ++i) {
- const HTMLToken::Attribute& attribute = attributes[i];
+ for (auto& attribute : attributes) {
if (attribute.name.isEmpty())
continue;
- // FIXME: We should be able to add the following ASSERT once we fix
- // https://bugs.webkit.org/show_bug.cgi?id=62971
- // ASSERT(attribute.nameRange.start);
- ASSERT(attribute.nameRange.end);
- ASSERT(attribute.valueRange.start);
- ASSERT(attribute.valueRange.end);
+ AtomicString localName(attribute.name);
- AtomicString value(attribute.value);
- const QualifiedName& name = nameForAttribute(attribute);
// FIXME: This is N^2 for the number of attributes.
- if (!findAttributeInVector(m_attributes, name))
- m_attributes.append(Attribute(name, value));
+ if (!hasAttribute(m_attributes, localName))
+ m_attributes.uncheckedAppend(Attribute(QualifiedName(nullAtom, localName, nullAtom), AtomicString(attribute.value)));
}
}
+inline AtomicHTMLToken::AtomicHTMLToken(HTMLToken& token)
+ : m_type(token.type())
+{
+ switch (m_type) {
+ case HTMLToken::Uninitialized:
+ ASSERT_NOT_REACHED();
+ return;
+ case HTMLToken::DOCTYPE:
+ m_name = AtomicString(token.name());
+ m_doctypeData = token.releaseDoctypeData();
+ return;
+ case HTMLToken::EndOfFile:
+ return;
+ case HTMLToken::StartTag:
+ case HTMLToken::EndTag:
+ m_selfClosing = token.selfClosing();
+ m_name = AtomicString(token.name());
+ initializeAttributes(token.attributes());
+ return;
+ case HTMLToken::Comment:
+ if (token.commentIsAll8BitData())
+ m_data = String::make8BitFrom16BitSource(token.comment());
+ else
+ m_data = String(token.comment());
+ return;
+ case HTMLToken::Character:
+ m_externalCharacters = token.characters().data();
+ m_externalCharactersLength = token.characters().size();
+ m_externalCharactersIsAll8BitData = token.charactersIsAll8BitData();
+ return;
+ }
+ ASSERT_NOT_REACHED();
+}
+
+inline AtomicHTMLToken::AtomicHTMLToken(HTMLToken::Type type, const AtomicString& name, Vector<Attribute>&& attributes)
+ : m_type(type)
+ , m_name(name)
+ , m_selfClosing(false)
+ , m_attributes(WTFMove(attributes))
+{
+ ASSERT(type == HTMLToken::StartTag || type == HTMLToken::EndTag);
}
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/CSSPreloadScanner.cpp b/Source/WebCore/html/parser/CSSPreloadScanner.cpp
index 75a7a93b1..8027948b1 100644
--- a/Source/WebCore/html/parser/CSSPreloadScanner.cpp
+++ b/Source/WebCore/html/parser/CSSPreloadScanner.cpp
@@ -29,7 +29,7 @@
#include "CSSPreloadScanner.h"
#include "HTMLParserIdioms.h"
-#include <wtf/TemporaryChange.h>
+#include <wtf/SetForScope.h>
namespace WebCore {
@@ -53,7 +53,7 @@ void CSSPreloadScanner::reset()
void CSSPreloadScanner::scan(const HTMLToken::DataVector& data, PreloadRequestStream& requests)
{
ASSERT(!m_requests);
- TemporaryChange<PreloadRequestStream*> change(m_requests, &requests);
+ SetForScope<PreloadRequestStream*> change(m_requests, &requests);
for (UChar c : data) {
if (m_state == DoneParsingImportRules)
@@ -97,7 +97,7 @@ inline void CSSPreloadScanner::tokenize(UChar c)
m_state = Comment;
break;
case RuleStart:
- if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
+ if (isASCIIAlpha(c)) {
m_rule.clear();
m_ruleValue.clear();
m_rule.append(c);
@@ -195,25 +195,18 @@ static String parseCSSStringOrURL(const UChar* characters, size_t length)
return String(characters + offset, reducedLength);
}
-template<unsigned referenceLength>
-static inline bool ruleEqualIgnoringCase(const Vector<UChar>& rule, const char (&reference)[referenceLength])
-{
- unsigned referenceCharactersLength = referenceLength - 1;
- return rule.size() == referenceCharactersLength && equalIgnoringCase(reference, rule.data(), referenceCharactersLength);
-}
-
void CSSPreloadScanner::emitRule()
{
- if (ruleEqualIgnoringCase(m_rule, "import")) {
+ StringView rule(m_rule.data(), m_rule.size());
+ if (equalLettersIgnoringASCIICase(rule, "import")) {
String url = parseCSSStringOrURL(m_ruleValue.data(), m_ruleValue.size());
if (!url.isEmpty()) {
- URL baseElementURL; // FIXME: This should be passed in from the HTMLPreloadScaner via scan()!
-
+ URL baseElementURL; // FIXME: This should be passed in from the HTMLPreloadScanner via scan(): without it we will get relative URLs wrong.
// FIXME: Should this be including the charset in the preload request?
- m_requests->append(std::make_unique<PreloadRequest>("css", url, baseElementURL, CachedResource::CSSStyleSheet, String()));
+ m_requests->append(std::make_unique<PreloadRequest>("css", url, baseElementURL, CachedResource::CSSStyleSheet, String(), PreloadRequest::ModuleScript::No));
}
m_state = Initial;
- } else if (ruleEqualIgnoringCase(m_rule, "charset"))
+ } else if (equalLettersIgnoringASCIICase(rule, "charset"))
m_state = Initial;
else
m_state = DoneParsingImportRules;
diff --git a/Source/WebCore/html/parser/CSSPreloadScanner.h b/Source/WebCore/html/parser/CSSPreloadScanner.h
index 1dca288d9..23eb8520a 100644
--- a/Source/WebCore/html/parser/CSSPreloadScanner.h
+++ b/Source/WebCore/html/parser/CSSPreloadScanner.h
@@ -24,8 +24,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CSSPreloadScanner_h
-#define CSSPreloadScanner_h
+#pragma once
#include "HTMLResourcePreloader.h"
#include "HTMLToken.h"
@@ -68,6 +67,4 @@ private:
PreloadRequestStream* m_requests;
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLConstructionSite.cpp b/Source/WebCore/html/parser/HTMLConstructionSite.cpp
index 0f0699826..f8dc5a518 100644
--- a/Source/WebCore/html/parser/HTMLConstructionSite.cpp
+++ b/Source/WebCore/html/parser/HTMLConstructionSite.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,6 +28,8 @@
#include "HTMLTreeBuilder.h"
#include "Comment.h"
+#include "CustomElementRegistry.h"
+#include "DOMWindow.h"
#include "DocumentFragment.h"
#include "DocumentType.h"
#include "Frame.h"
@@ -36,42 +38,61 @@
#include "HTMLElementFactory.h"
#include "HTMLFormElement.h"
#include "HTMLHtmlElement.h"
+#include "HTMLImageElement.h"
#include "HTMLOptGroupElement.h"
#include "HTMLOptionElement.h"
#include "HTMLParserIdioms.h"
+#include "HTMLPictureElement.h"
#include "HTMLScriptElement.h"
#include "HTMLTemplateElement.h"
+#include "HTMLUnknownElement.h"
+#include "JSCustomElementInterface.h"
#include "NotImplemented.h"
+#include "SVGElement.h"
#include "Text.h"
namespace WebCore {
using namespace HTMLNames;
-static inline void setAttributes(Element* element, AtomicHTMLToken* token, ParserContentPolicy parserContentPolicy)
+static inline void setAttributes(Element& element, Vector<Attribute>& attributes, ParserContentPolicy parserContentPolicy)
{
if (!scriptingContentIsAllowed(parserContentPolicy))
- element->stripScriptingAttributes(token->attributes());
- element->parserSetAttributes(token->attributes());
+ element.stripScriptingAttributes(attributes);
+ element.parserSetAttributes(attributes);
}
-static bool hasImpliedEndTag(const HTMLStackItem* item)
+static inline void setAttributes(Element& element, AtomicHTMLToken& token, ParserContentPolicy parserContentPolicy)
{
- return item->hasTagName(ddTag)
- || item->hasTagName(dtTag)
- || item->hasTagName(liTag)
- || isHTMLOptionElement(item->node())
- || isHTMLOptGroupElement(item->node())
- || item->hasTagName(pTag)
- || item->hasTagName(rpTag)
- || item->hasTagName(rtTag);
+ setAttributes(element, token.attributes(), parserContentPolicy);
}
-static bool shouldUseLengthLimit(const ContainerNode* node)
+static bool hasImpliedEndTag(const HTMLStackItem& item)
{
- return !node->hasTagName(scriptTag)
- && !node->hasTagName(styleTag)
- && !node->hasTagName(SVGNames::scriptTag);
+ return item.hasTagName(ddTag)
+ || item.hasTagName(dtTag)
+ || item.hasTagName(liTag)
+ || is<HTMLOptionElement>(item.node())
+ || is<HTMLOptGroupElement>(item.node())
+ || item.hasTagName(pTag)
+ || item.hasTagName(rbTag)
+ || item.hasTagName(rpTag)
+ || item.hasTagName(rtTag)
+ || item.hasTagName(rtcTag);
+}
+
+static bool shouldUseLengthLimit(const ContainerNode& node)
+{
+ return !node.hasTagName(scriptTag) && !node.hasTagName(styleTag) && !node.hasTagName(SVGNames::scriptTag);
+}
+
+static inline bool causesFosterParenting(const HTMLStackItem& item)
+{
+ return item.hasTagName(HTMLNames::tableTag)
+ || item.hasTagName(HTMLNames::tbodyTag)
+ || item.hasTagName(HTMLNames::tfootTag)
+ || item.hasTagName(HTMLNames::theadTag)
+ || item.hasTagName(HTMLNames::trTag);
}
static inline bool isAllWhitespace(const String& string)
@@ -81,18 +102,14 @@ static inline bool isAllWhitespace(const String& string)
static inline void insert(HTMLConstructionSiteTask& task)
{
-#if ENABLE(TEMPLATE_ELEMENT)
- if (task.parent->hasTagName(templateTag))
- task.parent = toHTMLTemplateElement(task.parent.get())->content();
-#endif
-
- if (ContainerNode* parent = task.child->parentNode())
- parent->parserRemoveChild(*task.child);
+ if (is<HTMLTemplateElement>(*task.parent))
+ task.parent = &downcast<HTMLTemplateElement>(*task.parent).content();
+ ASSERT(!task.child->parentNode());
if (task.nextChild)
- task.parent->parserInsertBefore(task.child.get(), task.nextChild.get());
+ task.parent->parserInsertBefore(*task.child, *task.nextChild);
else
- task.parent->parserAppendChild(task.child.get());
+ task.parent->parserAppendChild(*task.child);
}
static inline void executeInsertTask(HTMLConstructionSiteTask& task)
@@ -110,27 +127,43 @@ static inline void executeInsertTask(HTMLConstructionSiteTask& task)
static inline void executeReparentTask(HTMLConstructionSiteTask& task)
{
ASSERT(task.operation == HTMLConstructionSiteTask::Reparent);
+ ASSERT(!task.nextChild);
- if (ContainerNode* parent = task.child->parentNode())
+ if (auto* parent = task.child->parentNode())
parent->parserRemoveChild(*task.child);
- task.parent->parserAppendChild(task.child);
+ if (task.child->parentNode())
+ return;
+
+ task.parent->parserAppendChild(*task.child);
}
static inline void executeInsertAlreadyParsedChildTask(HTMLConstructionSiteTask& task)
{
ASSERT(task.operation == HTMLConstructionSiteTask::InsertAlreadyParsedChild);
+ if (ContainerNode* parent = task.child->parentNode())
+ parent->parserRemoveChild(*task.child);
+
+ if (task.child->parentNode())
+ return;
+
+ if (task.nextChild && task.nextChild->parentNode() != task.parent)
+ return;
+
insert(task);
}
-static inline void executeTakeAllChildrenTask(HTMLConstructionSiteTask& task)
+static inline void executeTakeAllChildrenAndReparentTask(HTMLConstructionSiteTask& task)
{
- ASSERT(task.operation == HTMLConstructionSiteTask::TakeAllChildren);
+ ASSERT(task.operation == HTMLConstructionSiteTask::TakeAllChildrenAndReparent);
+ ASSERT(!task.nextChild);
+
+ auto* furthestBlock = task.oldParent();
+ task.parent->takeAllChildrenFrom(furthestBlock);
- task.parent->takeAllChildrenFrom(task.oldParent());
- // Notice that we don't need to manually attach the moved children
- // because takeAllChildrenFrom does that work for us.
+ RELEASE_ASSERT(!task.parent->parentNode());
+ furthestBlock->parserAppendChild(*task.parent);
}
static inline void executeTask(HTMLConstructionSiteTask& task)
@@ -146,86 +179,79 @@ static inline void executeTask(HTMLConstructionSiteTask& task)
case HTMLConstructionSiteTask::Reparent:
executeReparentTask(task);
return;
- case HTMLConstructionSiteTask::TakeAllChildren:
- executeTakeAllChildrenTask(task);
+ case HTMLConstructionSiteTask::TakeAllChildrenAndReparent:
+ executeTakeAllChildrenAndReparentTask(task);
return;
}
ASSERT_NOT_REACHED();
}
-void HTMLConstructionSite::attachLater(ContainerNode* parent, PassRefPtr<Node> prpChild, bool selfClosing)
+void HTMLConstructionSite::attachLater(ContainerNode& parent, Ref<Node>&& child, bool selfClosing)
{
- ASSERT(scriptingContentIsAllowed(m_parserContentPolicy) || !prpChild.get()->isElementNode() || !toScriptElementIfPossible(toElement(prpChild.get())));
- ASSERT(pluginContentIsAllowed(m_parserContentPolicy) || !prpChild->isPluginElement());
-
- HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert);
- task.parent = parent;
- task.child = prpChild;
- task.selfClosing = selfClosing;
+ ASSERT(scriptingContentIsAllowed(m_parserContentPolicy) || !is<Element>(child.get()) || !isScriptElement(downcast<Element>(child.get())));
+ ASSERT(pluginContentIsAllowed(m_parserContentPolicy) || !child->isPluginElement());
if (shouldFosterParent()) {
- fosterParent(task.child);
+ fosterParent(WTFMove(child));
return;
}
+ HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert);
+ task.parent = &parent;
+ task.child = WTFMove(child);
+ task.selfClosing = selfClosing;
+
// Add as a sibling of the parent if we have reached the maximum depth allowed.
if (m_openElements.stackDepth() > m_maximumDOMTreeDepth && task.parent->parentNode())
task.parent = task.parent->parentNode();
ASSERT(task.parent);
- m_taskQueue.append(task);
+ m_taskQueue.append(WTFMove(task));
}
void HTMLConstructionSite::executeQueuedTasks()
{
- const size_t size = m_taskQueue.size();
- if (!size)
+ if (m_taskQueue.isEmpty())
return;
// Copy the task queue into a local variable in case executeTask
// re-enters the parser.
- TaskQueue queue = std::move(m_taskQueue);
+ TaskQueue queue = WTFMove(m_taskQueue);
- for (size_t i = 0; i < size; ++i)
- executeTask(queue[i]);
+ for (auto& task : queue)
+ executeTask(task);
// We might be detached now.
}
HTMLConstructionSite::HTMLConstructionSite(Document& document, ParserContentPolicy parserContentPolicy, unsigned maximumDOMTreeDepth)
- : m_document(&document)
- , m_attachmentRoot(&document)
+ : m_document(document)
+ , m_attachmentRoot(document)
, m_parserContentPolicy(parserContentPolicy)
, m_isParsingFragment(false)
, m_redirectAttachToFosterParent(false)
, m_maximumDOMTreeDepth(maximumDOMTreeDepth)
, m_inQuirksMode(document.inQuirksMode())
{
- ASSERT(m_document->isHTMLDocument() || m_document->isXHTMLDocument());
+ ASSERT(m_document.isHTMLDocument() || m_document.isXHTMLDocument());
}
HTMLConstructionSite::HTMLConstructionSite(DocumentFragment& fragment, ParserContentPolicy parserContentPolicy, unsigned maximumDOMTreeDepth)
- : m_document(&fragment.document())
- , m_attachmentRoot(&fragment)
+ : m_document(fragment.document())
+ , m_attachmentRoot(fragment)
, m_parserContentPolicy(parserContentPolicy)
, m_isParsingFragment(true)
, m_redirectAttachToFosterParent(false)
, m_maximumDOMTreeDepth(maximumDOMTreeDepth)
, m_inQuirksMode(fragment.document().inQuirksMode())
{
- ASSERT(m_document->isHTMLDocument() || m_document->isXHTMLDocument());
+ ASSERT(m_document.isHTMLDocument() || m_document.isXHTMLDocument());
}
HTMLConstructionSite::~HTMLConstructionSite()
{
}
-void HTMLConstructionSite::detach()
-{
- m_document = 0;
- m_attachmentRoot = 0;
-}
-
void HTMLConstructionSite::setForm(HTMLFormElement* form)
{
// This method should only be needed for HTMLTreeBuilder in the fragment case.
@@ -233,70 +259,71 @@ void HTMLConstructionSite::setForm(HTMLFormElement* form)
m_form = form;
}
-PassRefPtr<HTMLFormElement> HTMLConstructionSite::takeForm()
+RefPtr<HTMLFormElement> HTMLConstructionSite::takeForm()
{
- return m_form.release();
+ return WTFMove(m_form);
}
void HTMLConstructionSite::dispatchDocumentElementAvailableIfNeeded()
{
- ASSERT(m_document);
- if (m_document->frame() && !m_isParsingFragment)
- m_document->frame()->injectUserScripts(InjectAtDocumentStart);
+ if (m_isParsingFragment)
+ return;
+
+ if (auto* frame = m_document.frame())
+ frame->injectUserScripts(InjectAtDocumentStart);
}
-void HTMLConstructionSite::insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken&& token)
{
- RefPtr<HTMLHtmlElement> element = HTMLHtmlElement::create(*m_document);
- setAttributes(element.get(), token, m_parserContentPolicy);
- attachLater(m_attachmentRoot, element);
- m_openElements.pushHTMLHtmlElement(HTMLStackItem::create(element, token));
+ auto element = HTMLHtmlElement::create(m_document);
+ setAttributes(element, token, m_parserContentPolicy);
+ attachLater(m_attachmentRoot, element.copyRef());
+ m_openElements.pushHTMLHtmlElement(HTMLStackItem::create(element.copyRef(), WTFMove(token)));
executeQueuedTasks();
element->insertedByParser();
dispatchDocumentElementAvailableIfNeeded();
}
-void HTMLConstructionSite::mergeAttributesFromTokenIntoElement(AtomicHTMLToken* token, Element* element)
+void HTMLConstructionSite::mergeAttributesFromTokenIntoElement(AtomicHTMLToken&& token, Element& element)
{
- if (token->attributes().isEmpty())
+ if (token.attributes().isEmpty())
return;
- for (unsigned i = 0; i < token->attributes().size(); ++i) {
- const Attribute& tokenAttribute = token->attributes().at(i);
- if (!element->elementData() || !element->findAttributeByName(tokenAttribute.name()))
- element->setAttribute(tokenAttribute.name(), tokenAttribute.value());
+ for (auto& tokenAttribute : token.attributes()) {
+ if (!element.elementData() || !element.findAttributeByName(tokenAttribute.name()))
+ element.setAttribute(tokenAttribute.name(), tokenAttribute.value());
}
}
-void HTMLConstructionSite::insertHTMLHtmlStartTagInBody(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertHTMLHtmlStartTagInBody(AtomicHTMLToken&& token)
{
// Fragments do not have a root HTML element, so any additional HTML elements
// encountered during fragment parsing should be ignored.
if (m_isParsingFragment)
return;
- mergeAttributesFromTokenIntoElement(token, m_openElements.htmlElement());
+ mergeAttributesFromTokenIntoElement(WTFMove(token), m_openElements.htmlElement());
}
-void HTMLConstructionSite::insertHTMLBodyStartTagInBody(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertHTMLBodyStartTagInBody(AtomicHTMLToken&& token)
{
- mergeAttributesFromTokenIntoElement(token, m_openElements.bodyElement());
+ mergeAttributesFromTokenIntoElement(WTFMove(token), m_openElements.bodyElement());
}
void HTMLConstructionSite::setDefaultCompatibilityMode()
{
if (m_isParsingFragment)
return;
- if (m_document->isSrcdocDocument())
+ if (m_document.isSrcdocDocument())
return;
- setCompatibilityMode(Document::QuirksMode);
+ setCompatibilityMode(DocumentCompatibilityMode::QuirksMode);
}
-void HTMLConstructionSite::setCompatibilityMode(Document::CompatibilityMode mode)
+void HTMLConstructionSite::setCompatibilityMode(DocumentCompatibilityMode mode)
{
- m_inQuirksMode = (mode == Document::QuirksMode);
- m_document->setCompatibilityMode(mode);
+ m_inQuirksMode = (mode == DocumentCompatibilityMode::QuirksMode);
+ m_document.setCompatibilityMode(mode);
}
void HTMLConstructionSite::setCompatibilityModeFromDoctype(const String& name, const String& publicId, const String& systemId)
@@ -362,15 +389,15 @@ void HTMLConstructionSite::setCompatibilityModeFromDoctype(const String& name, c
|| publicId.startsWith("-//W3C//DTD HTML Experimental 970421//", false)
|| publicId.startsWith("-//W3C//DTD W3 HTML//", false)
|| publicId.startsWith("-//W3O//DTD W3 HTML 3.0//", false)
- || equalIgnoringCase(publicId, "-//W3O//DTD W3 HTML Strict 3.0//EN//")
+ || equalLettersIgnoringASCIICase(publicId, "-//w3o//dtd w3 html strict 3.0//en//")
|| publicId.startsWith("-//WebTechs//DTD Mozilla HTML 2.0//", false)
|| publicId.startsWith("-//WebTechs//DTD Mozilla HTML//", false)
- || equalIgnoringCase(publicId, "-/W3C/DTD HTML 4.0 Transitional/EN")
- || equalIgnoringCase(publicId, "HTML")
- || equalIgnoringCase(systemId, "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd")
+ || equalLettersIgnoringASCIICase(publicId, "-/w3c/dtd html 4.0 transitional/en")
+ || equalLettersIgnoringASCIICase(publicId, "html")
+ || equalLettersIgnoringASCIICase(systemId, "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd")
|| (systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Frameset//", false))
|| (systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Transitional//", false))) {
- setCompatibilityMode(Document::QuirksMode);
+ setCompatibilityMode(DocumentCompatibilityMode::QuirksMode);
return;
}
@@ -379,27 +406,27 @@ void HTMLConstructionSite::setCompatibilityModeFromDoctype(const String& name, c
|| publicId.startsWith("-//W3C//DTD XHTML 1.0 Transitional//", false)
|| (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Frameset//", false))
|| (!systemId.isEmpty() && publicId.startsWith("-//W3C//DTD HTML 4.01 Transitional//", false))) {
- setCompatibilityMode(Document::LimitedQuirksMode);
+ setCompatibilityMode(DocumentCompatibilityMode::LimitedQuirksMode);
return;
}
// Otherwise we are No Quirks Mode.
- setCompatibilityMode(Document::NoQuirksMode);
+ setCompatibilityMode(DocumentCompatibilityMode::NoQuirksMode);
}
void HTMLConstructionSite::finishedParsing()
{
- m_document->finishedParsing();
+ m_document.finishedParsing();
}
-void HTMLConstructionSite::insertDoctype(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertDoctype(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::DOCTYPE);
+ ASSERT(token.type() == HTMLToken::DOCTYPE);
+
+ String publicId = token.publicIdentifier();
+ String systemId = token.systemIdentifier();
- const String& publicId = StringImpl::create8BitIfPossible(token->publicIdentifier());
- const String& systemId = StringImpl::create8BitIfPossible(token->systemIdentifier());
- RefPtr<DocumentType> doctype = DocumentType::create(*m_document, token->name(), publicId, systemId);
- attachLater(m_attachmentRoot, doctype.release());
+ attachLater(m_attachmentRoot, DocumentType::create(m_document, token.name(), publicId, systemId));
// DOCTYPE nodes are only processed when parsing fragments w/o contextElements, which
// never occurs. However, if we ever chose to support such, this code is subtly wrong,
@@ -410,70 +437,88 @@ void HTMLConstructionSite::insertDoctype(AtomicHTMLToken* token)
if (m_isParsingFragment)
return;
- if (token->forceQuirks())
- setCompatibilityMode(Document::QuirksMode);
- else {
- setCompatibilityModeFromDoctype(token->name(), publicId, systemId);
- }
+ if (token.forceQuirks())
+ setCompatibilityMode(DocumentCompatibilityMode::QuirksMode);
+ else
+ setCompatibilityModeFromDoctype(token.name(), publicId, systemId);
}
-void HTMLConstructionSite::insertComment(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertComment(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::Comment);
- attachLater(currentNode(), Comment::create(ownerDocumentForCurrentNode(), token->comment()));
+ ASSERT(token.type() == HTMLToken::Comment);
+ attachLater(currentNode(), Comment::create(ownerDocumentForCurrentNode(), token.comment()));
}
-void HTMLConstructionSite::insertCommentOnDocument(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertCommentOnDocument(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::Comment);
- attachLater(m_attachmentRoot, Comment::create(*m_document, token->comment()));
+ ASSERT(token.type() == HTMLToken::Comment);
+ attachLater(m_attachmentRoot, Comment::create(m_document, token.comment()));
}
-void HTMLConstructionSite::insertCommentOnHTMLHtmlElement(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertCommentOnHTMLHtmlElement(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::Comment);
- ContainerNode* parent = m_openElements.rootNode();
- attachLater(parent, Comment::create(parent->document(), token->comment()));
+ ASSERT(token.type() == HTMLToken::Comment);
+ ContainerNode& parent = m_openElements.rootNode();
+ attachLater(parent, Comment::create(parent.document(), token.comment()));
}
-void HTMLConstructionSite::insertHTMLHeadElement(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertHTMLHeadElement(AtomicHTMLToken&& token)
{
ASSERT(!shouldFosterParent());
- m_head = HTMLStackItem::create(createHTMLElement(token), token);
+ m_head = HTMLStackItem::create(createHTMLElement(token), WTFMove(token));
attachLater(currentNode(), m_head->element());
- m_openElements.pushHTMLHeadElement(m_head);
+ m_openElements.pushHTMLHeadElement(*m_head);
}
-void HTMLConstructionSite::insertHTMLBodyElement(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertHTMLBodyElement(AtomicHTMLToken&& token)
{
ASSERT(!shouldFosterParent());
- RefPtr<Element> body = createHTMLElement(token);
- attachLater(currentNode(), body);
- m_openElements.pushHTMLBodyElement(HTMLStackItem::create(body.release(), token));
+ auto body = createHTMLElement(token);
+ attachLater(currentNode(), body.copyRef());
+ m_openElements.pushHTMLBodyElement(HTMLStackItem::create(WTFMove(body), WTFMove(token)));
+}
+
+void HTMLConstructionSite::insertHTMLFormElement(AtomicHTMLToken&& token, bool isDemoted)
+{
+ auto element = createHTMLElement(token);
+ auto& formElement = downcast<HTMLFormElement>(element.get());
+ // If there is no template element on the stack of open elements, set the
+ // form element pointer to point to the element created.
+ if (!openElements().hasTemplateInHTMLScope())
+ m_form = &formElement;
+ formElement.setDemoted(isDemoted);
+ attachLater(currentNode(), formElement);
+ m_openElements.push(HTMLStackItem::create(formElement, WTFMove(token)));
}
-void HTMLConstructionSite::insertHTMLFormElement(AtomicHTMLToken* token, bool isDemoted)
+void HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken&& token)
{
- RefPtr<Element> element = createHTMLElement(token);
- ASSERT(isHTMLFormElement(element.get()));
- RefPtr<HTMLFormElement> form = static_pointer_cast<HTMLFormElement>(element.release());
- if (!insideTemplateElement())
- m_form = form;
- form->setDemoted(isDemoted);
- attachLater(currentNode(), form);
- m_openElements.push(HTMLStackItem::create(form.release(), token));
+ auto element = createHTMLElement(token);
+ attachLater(currentNode(), element.copyRef());
+ m_openElements.push(HTMLStackItem::create(WTFMove(element), WTFMove(token)));
}
-void HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken* token)
+std::unique_ptr<CustomElementConstructionData> HTMLConstructionSite::insertHTMLElementOrFindCustomElementInterface(AtomicHTMLToken&& token)
{
- RefPtr<Element> element = createHTMLElement(token);
- attachLater(currentNode(), element);
- m_openElements.push(HTMLStackItem::create(element.release(), token));
+ JSCustomElementInterface* elementInterface = nullptr;
+ RefPtr<Element> element = createHTMLElementOrFindCustomElementInterface(token, &elementInterface);
+ if (UNLIKELY(elementInterface))
+ return std::make_unique<CustomElementConstructionData>(*elementInterface, token.name(), WTFMove(token.attributes()));
+ attachLater(currentNode(), *element);
+ m_openElements.push(HTMLStackItem::create(element.releaseNonNull(), WTFMove(token)));
+ return nullptr;
}
-void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertCustomElement(Ref<Element>&& element, const AtomicString& localName, Vector<Attribute>&& attributes)
{
- ASSERT(token->type() == HTMLToken::StartTag);
+ setAttributes(element, attributes, m_parserContentPolicy);
+ attachLater(currentNode(), element.copyRef());
+ m_openElements.push(HTMLStackItem::create(WTFMove(element), localName, WTFMove(attributes)));
+}
+
+void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken&& token)
+{
+ ASSERT(token.type() == HTMLToken::StartTag);
// Normally HTMLElementStack is responsible for calling finishParsingChildren,
// but self-closing elements are never in the element stack so the stack
// doesn't get a chance to tell them that we're done parsing their children.
@@ -482,16 +527,17 @@ void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken* token)
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#acknowledge-self-closing-flag
}
-void HTMLConstructionSite::insertFormattingElement(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertFormattingElement(AtomicHTMLToken&& token)
{
// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-stack-of-open-elements
// Possible active formatting elements include:
// a, b, big, code, em, font, i, nobr, s, small, strike, strong, tt, and u.
- insertHTMLElement(token);
- m_activeFormattingElements.append(currentElementRecord()->stackItem());
+ ASSERT(isFormattingTag(token.name()));
+ insertHTMLElement(WTFMove(token));
+ m_activeFormattingElements.append(currentStackItem());
}
-void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken* token)
+void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken&& token)
{
// http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#already-started
// http://html5.org/specs/dom-parsing.html#dom-range-createcontextualfragment
@@ -500,59 +546,55 @@ void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken* token)
// those flags or effects thereof.
const bool parserInserted = m_parserContentPolicy != AllowScriptingContentAndDoNotMarkAlreadyStarted;
const bool alreadyStarted = m_isParsingFragment && parserInserted;
- RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, ownerDocumentForCurrentNode(), parserInserted, alreadyStarted);
- setAttributes(element.get(), token, m_parserContentPolicy);
+ auto element = HTMLScriptElement::create(scriptTag, ownerDocumentForCurrentNode(), parserInserted, alreadyStarted);
+ setAttributes(element, token, m_parserContentPolicy);
if (scriptingContentIsAllowed(m_parserContentPolicy))
- attachLater(currentNode(), element);
- m_openElements.push(HTMLStackItem::create(element.release(), token));
+ attachLater(currentNode(), element.copyRef());
+ m_openElements.push(HTMLStackItem::create(WTFMove(element), WTFMove(token)));
}
-void HTMLConstructionSite::insertForeignElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
+void HTMLConstructionSite::insertForeignElement(AtomicHTMLToken&& token, const AtomicString& namespaceURI)
{
- ASSERT(token->type() == HTMLToken::StartTag);
+ ASSERT(token.type() == HTMLToken::StartTag);
notImplemented(); // parseError when xmlns or xmlns:xlink are wrong.
- RefPtr<Element> element = createElement(token, namespaceURI);
- if (scriptingContentIsAllowed(m_parserContentPolicy) || !toScriptElementIfPossible(element.get()))
- attachLater(currentNode(), element, token->selfClosing());
- if (!token->selfClosing())
- m_openElements.push(HTMLStackItem::create(element.release(), token, namespaceURI));
+ auto element = createElement(token, namespaceURI);
+ if (scriptingContentIsAllowed(m_parserContentPolicy) || !isScriptElement(element.get()))
+ attachLater(currentNode(), element.copyRef(), token.selfClosing());
+ if (!token.selfClosing())
+ m_openElements.push(HTMLStackItem::create(WTFMove(element), WTFMove(token), namespaceURI));
}
void HTMLConstructionSite::insertTextNode(const String& characters, WhitespaceMode whitespaceMode)
{
HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert);
- task.parent = currentNode();
+ task.parent = &currentNode();
if (shouldFosterParent())
findFosterSite(task);
-#if ENABLE(TEMPLATE_ELEMENT)
- if (task.parent->hasTagName(templateTag))
- task.parent = toHTMLTemplateElement(task.parent.get())->content();
-#endif
+ if (is<HTMLTemplateElement>(*task.parent))
+ task.parent = &downcast<HTMLTemplateElement>(*task.parent).content();
// Strings composed entirely of whitespace are likely to be repeated.
// Turn them into AtomicString so we share a single string for each.
- bool shouldUseAtomicString = whitespaceMode == AllWhitespace
- || (whitespaceMode == WhitespaceUnknown && isAllWhitespace(characters));
+ bool shouldUseAtomicString = whitespaceMode == AllWhitespace || (whitespaceMode == WhitespaceUnknown && isAllWhitespace(characters));
unsigned currentPosition = 0;
- unsigned lengthLimit = shouldUseLengthLimit(task.parent.get()) ? Text::defaultLengthLimit : std::numeric_limits<unsigned>::max();
+ unsigned lengthLimit = shouldUseLengthLimit(*task.parent) ? Text::defaultLengthLimit : std::numeric_limits<unsigned>::max();
// FIXME: Splitting text nodes into smaller chunks contradicts HTML5 spec, but is currently necessary
// for performance, see <https://bugs.webkit.org/show_bug.cgi?id=55898>.
Node* previousChild = task.nextChild ? task.nextChild->previousSibling() : task.parent->lastChild();
- if (previousChild && previousChild->isTextNode()) {
+ if (is<Text>(previousChild)) {
// FIXME: We're only supposed to append to this text node if it
// was the last text node inserted by the parser.
- Text* textNode = toText(previousChild);
- currentPosition = textNode->parserAppendData(characters, 0, lengthLimit);
+ currentPosition = downcast<Text>(*previousChild).parserAppendData(characters, 0, lengthLimit);
}
while (currentPosition < characters.length()) {
- RefPtr<Text> textNode = Text::createWithLengthLimit(task.parent->document(), shouldUseAtomicString ? AtomicString(characters).string() : characters, currentPosition, lengthLimit);
+ auto textNode = Text::createWithLengthLimit(task.parent->document(), shouldUseAtomicString ? AtomicString(characters).string() : characters, currentPosition, lengthLimit);
// If we have a whole string of unbreakable characters the above could lead to an infinite loop. Exceeding the length limit is the lesser evil.
if (!textNode->length()) {
String substring = characters.substring(currentPosition);
@@ -561,7 +603,7 @@ void HTMLConstructionSite::insertTextNode(const String& characters, WhitespaceMo
currentPosition += textNode->length();
ASSERT(currentPosition <= characters.length());
- task.child = textNode.release();
+ task.child = WTFMove(textNode);
executeTask(task);
}
@@ -570,126 +612,141 @@ void HTMLConstructionSite::insertTextNode(const String& characters, WhitespaceMo
void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord& newParent, HTMLElementStack::ElementRecord& child)
{
HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Reparent);
- task.parent = newParent.node();
- task.child = child.element();
- m_taskQueue.append(task);
-}
-
-void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord& newParent, HTMLStackItem& child)
-{
- HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Reparent);
- task.parent = newParent.node();
- task.child = child.element();
- m_taskQueue.append(task);
+ task.parent = &newParent.node();
+ task.child = &child.element();
+ m_taskQueue.append(WTFMove(task));
}
void HTMLConstructionSite::insertAlreadyParsedChild(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& child)
{
- if (newParent.causesFosterParenting()) {
- fosterParent(child.element());
- return;
- }
-
HTMLConstructionSiteTask task(HTMLConstructionSiteTask::InsertAlreadyParsedChild);
- task.parent = newParent.node();
- task.child = child.element();
- m_taskQueue.append(task);
+ if (causesFosterParenting(newParent)) {
+ findFosterSite(task);
+ ASSERT(task.parent);
+ } else
+ task.parent = &newParent.node();
+ task.child = &child.element();
+ m_taskQueue.append(WTFMove(task));
}
-void HTMLConstructionSite::takeAllChildren(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& oldParent)
+void HTMLConstructionSite::takeAllChildrenAndReparent(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& oldParent)
{
- HTMLConstructionSiteTask task(HTMLConstructionSiteTask::TakeAllChildren);
- task.parent = newParent.node();
- task.child = oldParent.node();
- m_taskQueue.append(task);
+ HTMLConstructionSiteTask task(HTMLConstructionSiteTask::TakeAllChildrenAndReparent);
+ task.parent = &newParent.node();
+ task.child = &oldParent.node();
+ m_taskQueue.append(WTFMove(task));
}
-PassRefPtr<Element> HTMLConstructionSite::createElement(AtomicHTMLToken* token, const AtomicString& namespaceURI)
+Ref<Element> HTMLConstructionSite::createElement(AtomicHTMLToken& token, const AtomicString& namespaceURI)
{
- QualifiedName tagName(nullAtom, token->name(), namespaceURI);
- RefPtr<Element> element = ownerDocumentForCurrentNode().createElement(tagName, true);
- setAttributes(element.get(), token, m_parserContentPolicy);
- return element.release();
+ QualifiedName tagName(nullAtom, token.name(), namespaceURI);
+ auto element = ownerDocumentForCurrentNode().createElement(tagName, true);
+ setAttributes(element, token, m_parserContentPolicy);
+ return element;
}
inline Document& HTMLConstructionSite::ownerDocumentForCurrentNode()
{
-#if ENABLE(TEMPLATE_ELEMENT)
- if (currentNode()->hasTagName(templateTag))
- return toHTMLTemplateElement(currentElement())->content()->document();
-#endif
- return currentNode()->document();
+ if (is<HTMLTemplateElement>(currentNode()))
+ return downcast<HTMLTemplateElement>(currentNode()).content().document();
+ return currentNode().document();
}
-inline bool HTMLConstructionSite::insideTemplateElement()
+RefPtr<Element> HTMLConstructionSite::createHTMLElementOrFindCustomElementInterface(AtomicHTMLToken& token, JSCustomElementInterface** customElementInterface)
{
- return !ownerDocumentForCurrentNode().frame();
-}
-
-PassRefPtr<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken* token)
-{
- QualifiedName tagName(nullAtom, token->name(), xhtmlNamespaceURI);
+ auto& localName = token.name();
// FIXME: This can't use HTMLConstructionSite::createElement because we
// have to pass the current form element. We should rework form association
// to occur after construction to allow better code sharing here.
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#create-an-element-for-the-token
Document& ownerDocument = ownerDocumentForCurrentNode();
bool insideTemplateElement = !ownerDocument.frame();
- RefPtr<Element> element = HTMLElementFactory::createElement(tagName, ownerDocument, insideTemplateElement ? nullptr : form(), true);
- setAttributes(element.get(), token, m_parserContentPolicy);
+ RefPtr<Element> element = HTMLElementFactory::createKnownElement(localName, ownerDocument, insideTemplateElement ? nullptr : form(), true);
+ if (UNLIKELY(!element)) {
+ auto* window = ownerDocument.domWindow();
+ if (customElementInterface && window) {
+ auto* registry = window->customElementRegistry();
+ if (UNLIKELY(registry)) {
+ if (auto* elementInterface = registry->findInterface(localName)) {
+ *customElementInterface = elementInterface;
+ return nullptr;
+ }
+ }
+ }
+
+ QualifiedName qualifiedName(nullAtom, localName, xhtmlNamespaceURI);
+ if (Document::validateCustomElementName(localName) == CustomElementNameValidationStatus::Valid) {
+ element = HTMLElement::create(qualifiedName, ownerDocument);
+ element->setIsCustomElementUpgradeCandidate();
+ } else
+ element = HTMLUnknownElement::create(qualifiedName, ownerDocument);
+ }
+ ASSERT(element);
+
+ // FIXME: This is a hack to connect images to pictures before the image has
+ // been inserted into the document. It can be removed once asynchronous image
+ // loading is working.
+ if (is<HTMLPictureElement>(currentNode()) && is<HTMLImageElement>(*element))
+ downcast<HTMLImageElement>(*element).setPictureElement(&downcast<HTMLPictureElement>(currentNode()));
+
+ setAttributes(*element, token, m_parserContentPolicy);
ASSERT(element->isHTMLElement());
- return element.release();
+ return element;
+}
+
+Ref<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken& token)
+{
+ RefPtr<Element> element = createHTMLElementOrFindCustomElementInterface(token, nullptr);
+ ASSERT(element);
+ return element.releaseNonNull();
}
-PassRefPtr<HTMLStackItem> HTMLConstructionSite::createElementFromSavedToken(HTMLStackItem* item)
+Ref<HTMLStackItem> HTMLConstructionSite::createElementFromSavedToken(HTMLStackItem& item)
{
- RefPtr<Element> element;
// NOTE: Moving from item -> token -> item copies the Attribute vector twice!
- AtomicHTMLToken fakeToken(HTMLToken::StartTag, item->localName(), item->attributes());
- if (item->namespaceURI() == HTMLNames::xhtmlNamespaceURI)
- element = createHTMLElement(&fakeToken);
- else
- element = createElement(&fakeToken, item->namespaceURI());
- return HTMLStackItem::create(element.release(), &fakeToken, item->namespaceURI());
+ AtomicHTMLToken fakeToken(HTMLToken::StartTag, item.localName(), Vector<Attribute>(item.attributes()));
+ ASSERT(item.namespaceURI() == HTMLNames::xhtmlNamespaceURI);
+ ASSERT(isFormattingTag(item.localName()));
+ return HTMLStackItem::create(createHTMLElement(fakeToken), WTFMove(fakeToken), item.namespaceURI());
}
-bool HTMLConstructionSite::indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const
+std::optional<unsigned> HTMLConstructionSite::indexOfFirstUnopenFormattingElement() const
{
if (m_activeFormattingElements.isEmpty())
- return false;
+ return std::nullopt;
unsigned index = m_activeFormattingElements.size();
do {
--index;
- const HTMLFormattingElementList::Entry& entry = m_activeFormattingElements.at(index);
+ const auto& entry = m_activeFormattingElements.at(index);
if (entry.isMarker() || m_openElements.contains(entry.element())) {
- firstUnopenElementIndex = index + 1;
- return firstUnopenElementIndex < m_activeFormattingElements.size();
+ unsigned firstUnopenElementIndex = index + 1;
+ return firstUnopenElementIndex < m_activeFormattingElements.size() ? firstUnopenElementIndex : std::optional<unsigned>(std::nullopt);
}
} while (index);
- firstUnopenElementIndex = index;
- return true;
+
+ return index;
}
void HTMLConstructionSite::reconstructTheActiveFormattingElements()
{
- unsigned firstUnopenElementIndex;
- if (!indexOfFirstUnopenFormattingElement(firstUnopenElementIndex))
+ std::optional<unsigned> firstUnopenElementIndex = indexOfFirstUnopenFormattingElement();
+ if (!firstUnopenElementIndex)
return;
- unsigned unopenEntryIndex = firstUnopenElementIndex;
- ASSERT(unopenEntryIndex < m_activeFormattingElements.size());
- for (; unopenEntryIndex < m_activeFormattingElements.size(); ++unopenEntryIndex) {
- HTMLFormattingElementList::Entry& unopenedEntry = m_activeFormattingElements.at(unopenEntryIndex);
- RefPtr<HTMLStackItem> reconstructed = createElementFromSavedToken(unopenedEntry.stackItem().get());
+ ASSERT(firstUnopenElementIndex.value() < m_activeFormattingElements.size());
+ for (unsigned unopenEntryIndex = firstUnopenElementIndex.value(); unopenEntryIndex < m_activeFormattingElements.size(); ++unopenEntryIndex) {
+ auto& unopenedEntry = m_activeFormattingElements.at(unopenEntryIndex);
+ ASSERT(unopenedEntry.stackItem());
+ auto reconstructed = createElementFromSavedToken(*unopenedEntry.stackItem());
attachLater(currentNode(), reconstructed->node());
- m_openElements.push(reconstructed);
- unopenedEntry.replaceElement(reconstructed.release());
+ m_openElements.push(reconstructed.copyRef());
+ unopenedEntry.replaceElement(WTFMove(reconstructed));
}
}
void HTMLConstructionSite::generateImpliedEndTagsWithExclusion(const AtomicString& tagName)
{
- while (hasImpliedEndTag(currentStackItem()) && !currentStackItem()->matchesHTMLTag(tagName))
+ while (hasImpliedEndTag(currentStackItem()) && !currentStackItem().matchesHTMLTag(tagName))
m_openElements.pop();
}
@@ -699,60 +756,47 @@ void HTMLConstructionSite::generateImpliedEndTags()
m_openElements.pop();
}
-bool HTMLConstructionSite::inQuirksMode()
-{
- return m_inQuirksMode;
-}
-
void HTMLConstructionSite::findFosterSite(HTMLConstructionSiteTask& task)
{
-#if ENABLE(TEMPLATE_ELEMENT)
// When a node is to be foster parented, the last template element with no table element is below it in the stack of open elements is the foster parent element (NOT the template's parent!)
- HTMLElementStack::ElementRecord* lastTemplateElement = m_openElements.topmost(templateTag.localName());
+ auto* lastTemplateElement = m_openElements.topmost(templateTag.localName());
if (lastTemplateElement && !m_openElements.inTableScope(tableTag)) {
- task.parent = lastTemplateElement->element();
+ task.parent = &lastTemplateElement->element();
return;
}
-#endif
-
- HTMLElementStack::ElementRecord* lastTableElementRecord = m_openElements.topmost(tableTag.localName());
- if (lastTableElementRecord) {
- Element* lastTableElement = lastTableElementRecord->element();
- ContainerNode* parent = lastTableElement->parentNode();
+ if (auto* lastTableElementRecord = m_openElements.topmost(tableTag.localName())) {
+ auto& lastTableElement = lastTableElementRecord->element();
+ auto* parent = lastTableElement.parentNode();
// When parsing HTML fragments, we skip step 4.2 ("Let root be a new html element with no attributes") for efficiency,
// and instead use the DocumentFragment as a root node. So we must treat the root node (DocumentFragment) as if it is a html element here.
- bool parentCanBeFosterParent = parent && (parent->isElementNode() || (m_isParsingFragment && parent == m_openElements.rootNode()));
-#if ENABLE(TEMPLATE_ELEMENT)
- parentCanBeFosterParent = parentCanBeFosterParent || (parent && parent->isDocumentFragment() && toDocumentFragment(parent)->isTemplateContent());
-#endif
+ bool parentCanBeFosterParent = parent && (parent->isElementNode() || (m_isParsingFragment && parent == &m_openElements.rootNode()));
+ parentCanBeFosterParent = parentCanBeFosterParent || (is<DocumentFragment>(parent) && downcast<DocumentFragment>(parent)->isTemplateContent());
if (parentCanBeFosterParent) {
task.parent = parent;
- task.nextChild = lastTableElement;
+ task.nextChild = &lastTableElement;
return;
}
- task.parent = lastTableElementRecord->next()->element();
+ task.parent = &lastTableElementRecord->next()->element();
return;
}
// Fragment case
- task.parent = m_openElements.rootNode(); // DocumentFragment
+ task.parent = &m_openElements.rootNode(); // DocumentFragment
}
bool HTMLConstructionSite::shouldFosterParent() const
{
- return m_redirectAttachToFosterParent
- && currentStackItem()->isElementNode()
- && currentStackItem()->causesFosterParenting();
+ return m_redirectAttachToFosterParent && causesFosterParenting(currentStackItem());
}
-void HTMLConstructionSite::fosterParent(PassRefPtr<Node> node)
+void HTMLConstructionSite::fosterParent(Ref<Node>&& node)
{
HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert);
findFosterSite(task);
- task.child = node;
+ task.child = WTFMove(node);
ASSERT(task.parent);
- m_taskQueue.append(task);
+ m_taskQueue.append(WTFMove(task));
}
}
diff --git a/Source/WebCore/html/parser/HTMLConstructionSite.h b/Source/WebCore/html/parser/HTMLConstructionSite.h
index acd4c823e..96e64cfc7 100644
--- a/Source/WebCore/html/parser/HTMLConstructionSite.h
+++ b/Source/WebCore/html/parser/HTMLConstructionSite.h
@@ -24,15 +24,14 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLConstructionSite_h
-#define HTMLConstructionSite_h
+#pragma once
#include "FragmentScriptingPermission.h"
#include "HTMLElementStack.h"
#include "HTMLFormattingElementList.h"
#include <wtf/Noncopyable.h>
-#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
+#include <wtf/SetForScope.h>
#include <wtf/Vector.h>
namespace WebCore {
@@ -42,7 +41,7 @@ struct HTMLConstructionSiteTask {
Insert,
InsertAlreadyParsedChild,
Reparent,
- TakeAllChildren,
+ TakeAllChildrenAndReparent,
};
explicit HTMLConstructionSiteTask(Operation op)
@@ -56,7 +55,7 @@ struct HTMLConstructionSiteTask {
// It's sort of ugly, but we store the |oldParent| in the |child| field
// of the task so that we don't bloat the HTMLConstructionSiteTask
// object in the common case of the Insert operation.
- return toContainerNode(child.get());
+ return downcast<ContainerNode>(child.get());
}
Operation operation;
@@ -81,9 +80,11 @@ enum WhitespaceMode {
};
class AtomicHTMLToken;
+struct CustomElementConstructionData;
class Document;
class Element;
class HTMLFormElement;
+class JSCustomElementInterface;
class HTMLConstructionSite {
WTF_MAKE_NONCOPYABLE(HTMLConstructionSite);
@@ -92,120 +93,112 @@ public:
HTMLConstructionSite(DocumentFragment&, ParserContentPolicy, unsigned maximumDOMTreeDepth);
~HTMLConstructionSite();
- void detach();
void executeQueuedTasks();
void setDefaultCompatibilityMode();
void finishedParsing();
- void insertDoctype(AtomicHTMLToken*);
- void insertComment(AtomicHTMLToken*);
- void insertCommentOnDocument(AtomicHTMLToken*);
- void insertCommentOnHTMLHtmlElement(AtomicHTMLToken*);
- void insertHTMLElement(AtomicHTMLToken*);
- void insertSelfClosingHTMLElement(AtomicHTMLToken*);
- void insertFormattingElement(AtomicHTMLToken*);
- void insertHTMLHeadElement(AtomicHTMLToken*);
- void insertHTMLBodyElement(AtomicHTMLToken*);
- void insertHTMLFormElement(AtomicHTMLToken*, bool isDemoted = false);
- void insertScriptElement(AtomicHTMLToken*);
+ void insertDoctype(AtomicHTMLToken&&);
+ void insertComment(AtomicHTMLToken&&);
+ void insertCommentOnDocument(AtomicHTMLToken&&);
+ void insertCommentOnHTMLHtmlElement(AtomicHTMLToken&&);
+ void insertHTMLElement(AtomicHTMLToken&&);
+ std::unique_ptr<CustomElementConstructionData> insertHTMLElementOrFindCustomElementInterface(AtomicHTMLToken&&);
+ void insertCustomElement(Ref<Element>&&, const AtomicString& localName, Vector<Attribute>&&);
+ void insertSelfClosingHTMLElement(AtomicHTMLToken&&);
+ void insertFormattingElement(AtomicHTMLToken&&);
+ void insertHTMLHeadElement(AtomicHTMLToken&&);
+ void insertHTMLBodyElement(AtomicHTMLToken&&);
+ void insertHTMLFormElement(AtomicHTMLToken&&, bool isDemoted = false);
+ void insertScriptElement(AtomicHTMLToken&&);
void insertTextNode(const String&, WhitespaceMode = WhitespaceUnknown);
- void insertForeignElement(AtomicHTMLToken*, const AtomicString& namespaceURI);
+ void insertForeignElement(AtomicHTMLToken&&, const AtomicString& namespaceURI);
- void insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken*);
- void insertHTMLHtmlStartTagInBody(AtomicHTMLToken*);
- void insertHTMLBodyStartTagInBody(AtomicHTMLToken*);
+ void insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken&&);
+ void insertHTMLHtmlStartTagInBody(AtomicHTMLToken&&);
+ void insertHTMLBodyStartTagInBody(AtomicHTMLToken&&);
void reparent(HTMLElementStack::ElementRecord& newParent, HTMLElementStack::ElementRecord& child);
- void reparent(HTMLElementStack::ElementRecord& newParent, HTMLStackItem& child);
// insertAlreadyParsedChild assumes that |child| has already been parsed (i.e., we're just
// moving it around in the tree rather than parsing it for the first time). That means
// this function doesn't call beginParsingChildren / finishParsingChildren.
void insertAlreadyParsedChild(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& child);
- void takeAllChildren(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& oldParent);
+ void takeAllChildrenAndReparent(HTMLStackItem& newParent, HTMLElementStack::ElementRecord& oldParent);
- PassRefPtr<HTMLStackItem> createElementFromSavedToken(HTMLStackItem*);
+ Ref<HTMLStackItem> createElementFromSavedToken(HTMLStackItem&);
bool shouldFosterParent() const;
- void fosterParent(PassRefPtr<Node>);
+ void fosterParent(Ref<Node>&&);
- bool indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const;
+ std::optional<unsigned> indexOfFirstUnopenFormattingElement() const;
void reconstructTheActiveFormattingElements();
void generateImpliedEndTags();
void generateImpliedEndTagsWithExclusion(const AtomicString& tagName);
- bool inQuirksMode();
+ bool inQuirksMode() { return m_inQuirksMode; }
bool isEmpty() const { return !m_openElements.stackDepth(); }
- HTMLElementStack::ElementRecord* currentElementRecord() const { return m_openElements.topRecord(); }
- Element* currentElement() const { return m_openElements.top(); }
- ContainerNode* currentNode() const { return m_openElements.topNode(); }
- HTMLStackItem* currentStackItem() const { return m_openElements.topStackItem(); }
+ Element& currentElement() const { return m_openElements.top(); }
+ ContainerNode& currentNode() const { return m_openElements.topNode(); }
+ HTMLStackItem& currentStackItem() const { return m_openElements.topStackItem(); }
HTMLStackItem* oneBelowTop() const { return m_openElements.oneBelowTop(); }
Document& ownerDocumentForCurrentNode();
- bool insideTemplateElement();
- HTMLElementStack* openElements() const { return &m_openElements; }
- HTMLFormattingElementList* activeFormattingElements() const { return &m_activeFormattingElements; }
- bool currentIsRootNode() { return m_openElements.topNode() == m_openElements.rootNode(); }
+ HTMLElementStack& openElements() const { return m_openElements; }
+ HTMLFormattingElementList& activeFormattingElements() const { return m_activeFormattingElements; }
+ bool currentIsRootNode() { return &m_openElements.topNode() == &m_openElements.rootNode(); }
- Element* head() const { return m_head->element(); }
+ Element& head() const { return m_head->element(); }
HTMLStackItem* headStackItem() const { return m_head.get(); }
void setForm(HTMLFormElement*);
HTMLFormElement* form() const { return m_form.get(); }
- PassRefPtr<HTMLFormElement> takeForm();
+ RefPtr<HTMLFormElement> takeForm();
ParserContentPolicy parserContentPolicy() { return m_parserContentPolicy; }
-#if PLATFORM(IOS)
- bool isTelephoneNumberParsingEnabled() { return m_document->isTelephoneNumberParsingEnabled(); }
+#if ENABLE(TELEPHONE_NUMBER_DETECTION)
+ bool isTelephoneNumberParsingEnabled() { return m_document.isTelephoneNumberParsingEnabled(); }
#endif
class RedirectToFosterParentGuard {
WTF_MAKE_NONCOPYABLE(RedirectToFosterParentGuard);
public:
- RedirectToFosterParentGuard(HTMLConstructionSite& tree)
- : m_tree(tree)
- , m_wasRedirectingBefore(tree.m_redirectAttachToFosterParent)
- {
- m_tree.m_redirectAttachToFosterParent = true;
- }
-
- ~RedirectToFosterParentGuard()
- {
- m_tree.m_redirectAttachToFosterParent = m_wasRedirectingBefore;
- }
+ explicit RedirectToFosterParentGuard(HTMLConstructionSite& tree)
+ : m_redirectAttachToFosterParentChange(tree.m_redirectAttachToFosterParent, true)
+ { }
private:
- HTMLConstructionSite& m_tree;
- bool m_wasRedirectingBefore;
+ SetForScope<bool> m_redirectAttachToFosterParentChange;
};
+ static bool isFormattingTag(const AtomicString&);
+
private:
// In the common case, this queue will have only one task because most
// tokens produce only one DOM mutation.
typedef Vector<HTMLConstructionSiteTask, 1> TaskQueue;
- void setCompatibilityMode(Document::CompatibilityMode);
+ void setCompatibilityMode(DocumentCompatibilityMode);
void setCompatibilityModeFromDoctype(const String& name, const String& publicId, const String& systemId);
- void attachLater(ContainerNode* parent, PassRefPtr<Node> child, bool selfClosing = false);
+ void attachLater(ContainerNode& parent, Ref<Node>&& child, bool selfClosing = false);
void findFosterSite(HTMLConstructionSiteTask&);
- PassRefPtr<Element> createHTMLElement(AtomicHTMLToken*);
- PassRefPtr<Element> createElement(AtomicHTMLToken*, const AtomicString& namespaceURI);
+ RefPtr<Element> createHTMLElementOrFindCustomElementInterface(AtomicHTMLToken&, JSCustomElementInterface**);
+ Ref<Element> createHTMLElement(AtomicHTMLToken&);
+ Ref<Element> createElement(AtomicHTMLToken&, const AtomicString& namespaceURI);
- void mergeAttributesFromTokenIntoElement(AtomicHTMLToken*, Element*);
+ void mergeAttributesFromTokenIntoElement(AtomicHTMLToken&&, Element&);
void dispatchDocumentElementAvailableIfNeeded();
- Document* m_document;
+ Document& m_document;
// This is the root ContainerNode to which the parser attaches all newly
// constructed nodes. It points to a DocumentFragment when parsing fragments
// and a Document in all other cases.
- ContainerNode* m_attachmentRoot;
+ ContainerNode& m_attachmentRoot;
RefPtr<HTMLStackItem> m_head;
RefPtr<HTMLFormElement> m_form;
@@ -229,5 +222,3 @@ private:
};
} // namespace WebCore
-
-#endif
diff --git a/Source/WebCore/html/parser/HTMLDocumentParser.cpp b/Source/WebCore/html/parser/HTMLDocumentParser.cpp
index 488862049..c3846db05 100644
--- a/Source/WebCore/html/parser/HTMLDocumentParser.cpp
+++ b/Source/WebCore/html/parser/HTMLDocumentParser.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,99 +27,70 @@
#include "config.h"
#include "HTMLDocumentParser.h"
-#include "ContentSecurityPolicy.h"
#include "DocumentFragment.h"
-#include "DocumentLoader.h"
#include "Frame.h"
+#include "HTMLDocument.h"
#include "HTMLParserScheduler.h"
+#include "HTMLPreloadScanner.h"
#include "HTMLScriptRunner.h"
#include "HTMLTreeBuilder.h"
-#include "HTMLDocument.h"
-#include "InspectorInstrumentation.h"
-#include "Settings.h"
-#include <wtf/Ref.h>
+#include "HTMLUnknownElement.h"
+#include "JSCustomElementInterface.h"
+#include "ScriptElement.h"
namespace WebCore {
using namespace HTMLNames;
-// This is a direct transcription of step 4 from:
-// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#fragment-case
-static HTMLTokenizer::State tokenizerStateForContextElement(Element* contextElement, bool reportErrors, const HTMLParserOptions& options)
-{
- if (!contextElement)
- return HTMLTokenizer::DataState;
-
- const QualifiedName& contextTag = contextElement->tagQName();
-
- if (contextTag.matches(titleTag) || contextTag.matches(textareaTag))
- return HTMLTokenizer::RCDATAState;
- if (contextTag.matches(styleTag)
- || contextTag.matches(xmpTag)
- || contextTag.matches(iframeTag)
- || (contextTag.matches(noembedTag) && options.pluginsEnabled)
- || (contextTag.matches(noscriptTag) && options.scriptEnabled)
- || contextTag.matches(noframesTag))
- return reportErrors ? HTMLTokenizer::RAWTEXTState : HTMLTokenizer::PLAINTEXTState;
- if (contextTag.matches(scriptTag))
- return reportErrors ? HTMLTokenizer::ScriptDataState : HTMLTokenizer::PLAINTEXTState;
- if (contextTag.matches(plaintextTag))
- return HTMLTokenizer::PLAINTEXTState;
- return HTMLTokenizer::DataState;
-}
-
HTMLDocumentParser::HTMLDocumentParser(HTMLDocument& document)
: ScriptableDocumentParser(document)
, m_options(document)
- , m_token(std::make_unique<HTMLToken>())
- , m_tokenizer(std::make_unique<HTMLTokenizer>(m_options))
+ , m_tokenizer(m_options)
, m_scriptRunner(std::make_unique<HTMLScriptRunner>(document, static_cast<HTMLScriptRunnerHost&>(*this)))
, m_treeBuilder(std::make_unique<HTMLTreeBuilder>(*this, document, parserContentPolicy(), m_options))
, m_parserScheduler(std::make_unique<HTMLParserScheduler>(*this))
, m_xssAuditorDelegate(document)
, m_preloader(std::make_unique<HTMLResourcePreloader>(document))
- , m_endWasDelayed(false)
- , m_haveBackgroundParser(false)
- , m_pumpSessionNestingLevel(0)
{
- ASSERT(m_token);
- ASSERT(m_tokenizer);
}
-// FIXME: Member variables should be grouped into self-initializing structs to
-// minimize code duplication between these constructors.
-HTMLDocumentParser::HTMLDocumentParser(DocumentFragment& fragment, Element* contextElement, ParserContentPolicy parserContentPolicy)
- : ScriptableDocumentParser(fragment.document(), parserContentPolicy)
+Ref<HTMLDocumentParser> HTMLDocumentParser::create(HTMLDocument& document)
+{
+ return adoptRef(*new HTMLDocumentParser(document));
+}
+
+inline HTMLDocumentParser::HTMLDocumentParser(DocumentFragment& fragment, Element& contextElement, ParserContentPolicy rawPolicy)
+ : ScriptableDocumentParser(fragment.document(), rawPolicy)
, m_options(fragment.document())
- , m_token(std::make_unique<HTMLToken>())
- , m_tokenizer(std::make_unique<HTMLTokenizer>(m_options))
- , m_treeBuilder(std::make_unique<HTMLTreeBuilder>(*this, fragment, contextElement, this->parserContentPolicy(), m_options))
+ , m_tokenizer(m_options)
+ , m_treeBuilder(std::make_unique<HTMLTreeBuilder>(*this, fragment, contextElement, parserContentPolicy(), m_options))
, m_xssAuditorDelegate(fragment.document())
- , m_endWasDelayed(false)
- , m_haveBackgroundParser(false)
- , m_pumpSessionNestingLevel(0)
{
- bool reportErrors = false; // For now document fragment parsing never reports errors.
- m_tokenizer->setState(tokenizerStateForContextElement(contextElement, reportErrors, m_options));
+ // https://html.spec.whatwg.org/multipage/syntax.html#parsing-html-fragments
+ if (contextElement.isHTMLElement())
+ m_tokenizer.updateStateFor(contextElement.tagQName().localName());
m_xssAuditor.initForFragment();
}
+inline Ref<HTMLDocumentParser> HTMLDocumentParser::create(DocumentFragment& fragment, Element& contextElement, ParserContentPolicy parserContentPolicy)
+{
+ return adoptRef(*new HTMLDocumentParser(fragment, contextElement, parserContentPolicy));
+}
+
HTMLDocumentParser::~HTMLDocumentParser()
{
ASSERT(!m_parserScheduler);
ASSERT(!m_pumpSessionNestingLevel);
ASSERT(!m_preloadScanner);
ASSERT(!m_insertionPreloadScanner);
- ASSERT(!m_haveBackgroundParser);
}
void HTMLDocumentParser::detach()
{
- DocumentParser::detach();
+ ScriptableDocumentParser::detach();
if (m_scriptRunner)
m_scriptRunner->detach();
- m_treeBuilder->detach();
// FIXME: It seems wrong that we would have a preload scanner here.
// Yet during fast/dom/HTMLScriptElement/script-load-events.html we do.
m_preloadScanner = nullptr;
@@ -133,16 +105,14 @@ void HTMLDocumentParser::stopParsing()
}
// This kicks off "Once the user agent stops parsing" as described by:
-// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#the-end
+// https://html.spec.whatwg.org/multipage/syntax.html#the-end
void HTMLDocumentParser::prepareToStopParsing()
{
- // FIXME: It may not be correct to disable this for the background parser.
- // That means hasInsertionPoint() may not be correct in some cases.
- ASSERT(!hasInsertionPoint() || m_haveBackgroundParser);
+ ASSERT(!hasInsertionPoint());
// pumpTokenizer can cause this parser to be detached from the Document,
// but we need to ensure it isn't deleted yet.
- Ref<HTMLDocumentParser> protect(*this);
+ Ref<HTMLDocumentParser> protectedThis(*this);
// NOTE: This pump should only ever emit buffered character tokens,
// so ForceSynchronous vs. AllowYield should be meaningless.
@@ -165,6 +135,16 @@ void HTMLDocumentParser::prepareToStopParsing()
attemptToRunDeferredScriptsAndEnd();
}
+inline bool HTMLDocumentParser::inPumpSession() const
+{
+ return m_pumpSessionNestingLevel > 0;
+}
+
+inline bool HTMLDocumentParser::shouldDelayEnd() const
+{
+ return inPumpSession() || isWaitingForScripts() || isScheduledForResume() || isExecutingScript();
+}
+
bool HTMLDocumentParser::isParsingFragment() const
{
return m_treeBuilder->isParsingFragment();
@@ -172,7 +152,7 @@ bool HTMLDocumentParser::isParsingFragment() const
bool HTMLDocumentParser::processingData() const
{
- return isScheduledForResume() || inPumpSession() || m_haveBackgroundParser;
+ return isScheduledForResume() || inPumpSession();
}
void HTMLDocumentParser::pumpTokenizerIfPossible(SynchronousMode mode)
@@ -199,10 +179,10 @@ void HTMLDocumentParser::resumeParsingAfterYield()
{
// pumpTokenizer can cause this parser to be detached from the Document,
// but we need to ensure it isn't deleted yet.
- Ref<HTMLDocumentParser> protect(*this);
+ Ref<HTMLDocumentParser> protectedThis(*this);
- // We should never be here unless we can pump immediately. Call pumpTokenizer()
- // directly so that ASSERTS will fire if we're wrong.
+ // We should never be here unless we can pump immediately.
+ // Call pumpTokenizer() directly so that ASSERTS will fire if we're wrong.
pumpTokenizer(AllowYield);
endIfDelayed();
}
@@ -211,53 +191,23 @@ void HTMLDocumentParser::runScriptsForPausedTreeBuilder()
{
ASSERT(scriptingContentIsAllowed(parserContentPolicy()));
- TextPosition scriptStartPosition = TextPosition::belowRangePosition();
- RefPtr<Element> scriptElement = m_treeBuilder->takeScriptToProcess(scriptStartPosition);
- // We will not have a scriptRunner when parsing a DocumentFragment.
- if (m_scriptRunner)
- m_scriptRunner->execute(scriptElement.release(), scriptStartPosition);
-}
-
-bool HTMLDocumentParser::canTakeNextToken(SynchronousMode mode, PumpSession& session)
-{
- if (isStopped())
- return false;
-
- ASSERT(!m_haveBackgroundParser || mode == ForceSynchronous);
+ if (std::unique_ptr<CustomElementConstructionData> constructionData = m_treeBuilder->takeCustomElementConstructionData()) {
+ ASSERT(!m_treeBuilder->hasParserBlockingScriptWork());
- if (isWaitingForScripts()) {
- if (mode == AllowYield)
- m_parserScheduler->checkForYieldBeforeScript(session);
-
- // If we don't run the script, we cannot allow the next token to be taken.
- if (session.needsYield)
- return false;
-
- // If we're paused waiting for a script, we try to execute scripts before continuing.
- runScriptsForPausedTreeBuilder();
- if (isWaitingForScripts() || isStopped())
- return false;
+ // https://html.spec.whatwg.org/#create-an-element-for-the-token
+ auto& elementInterface = constructionData->elementInterface.get();
+ auto newElement = elementInterface.constructElementWithFallback(*document(), constructionData->name);
+ m_treeBuilder->didCreateCustomOrCallbackElement(WTFMove(newElement), *constructionData);
+ return;
}
- // FIXME: It's wrong for the HTMLDocumentParser to reach back to the
- // Frame, but this approach is how the old parser handled
- // stopping when the page assigns window.location. What really
- // should happen is that assigning window.location causes the
- // parser to stop parsing cleanly. The problem is we're not
- // perpared to do that at every point where we run JavaScript.
- if (!isParsingFragment()
- && document()->frame() && document()->frame()->navigationScheduler().locationChangePending())
- return false;
-
- if (mode == AllowYield)
- m_parserScheduler->checkForYieldBeforeToken(session);
-
- return true;
-}
-
-void HTMLDocumentParser::forcePlaintextForTextDocument()
-{
- m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState);
+ TextPosition scriptStartPosition = TextPosition::belowRangePosition();
+ if (auto scriptElement = m_treeBuilder->takeScriptToProcess(scriptStartPosition)) {
+ ASSERT(!m_treeBuilder->hasParserBlockingScriptWork());
+ // We will not have a scriptRunner when parsing a DocumentFragment.
+ if (m_scriptRunner)
+ m_scriptRunner->execute(scriptElement.releaseNonNull(), scriptStartPosition);
+ }
}
Document* HTMLDocumentParser::contextForParsingSession()
@@ -265,50 +215,67 @@ Document* HTMLDocumentParser::contextForParsingSession()
// The parsing session should interact with the document only when parsing
// non-fragments. Otherwise, we might delay the load event mistakenly.
if (isParsingFragment())
- return 0;
+ return nullptr;
return document();
}
-void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
+bool HTMLDocumentParser::pumpTokenizerLoop(SynchronousMode mode, bool parsingFragment, PumpSession& session)
{
- ASSERT(!isStopped());
- ASSERT(!isScheduledForResume());
- // ASSERT that this object is both attached to the Document and protected.
- ASSERT(refCount() >= 2);
- ASSERT(m_tokenizer);
- ASSERT(m_token);
- ASSERT(!m_haveBackgroundParser || mode == ForceSynchronous);
-
- PumpSession session(m_pumpSessionNestingLevel, contextForParsingSession());
+ do {
+ if (UNLIKELY(isWaitingForScripts())) {
+ if (mode == AllowYield && m_parserScheduler->shouldYieldBeforeExecutingScript(session))
+ return true;
+ runScriptsForPausedTreeBuilder();
+ // If we're paused waiting for a script, we try to execute scripts before continuing.
+ if (isWaitingForScripts() || isStopped())
+ return false;
+ }
- // We tell the InspectorInstrumentation about every pump, even if we
- // end up pumping nothing. It can filter out empty pumps itself.
- // FIXME: m_input.current().length() is only accurate if we
- // end up parsing the whole buffer in this pump. We should pass how
- // much we parsed as part of didWriteHTML instead of willWriteHTML.
- InspectorInstrumentationCookie cookie = InspectorInstrumentation::willWriteHTML(document(), m_input.current().currentLine().zeroBasedInt());
+ // FIXME: It's wrong for the HTMLDocumentParser to reach back to the Frame, but this approach is
+ // how the parser has always handled stopping when the page assigns window.location. What should
+ // happen instead is that assigning window.location causes the parser to stop parsing cleanly.
+ // The problem is we're not prepared to do that at every point where we run JavaScript.
+ if (UNLIKELY(!parsingFragment && document()->frame() && document()->frame()->navigationScheduler().locationChangePending()))
+ return false;
- m_xssAuditor.init(document(), &m_xssAuditorDelegate);
+ if (UNLIKELY(mode == AllowYield && m_parserScheduler->shouldYieldBeforeToken(session)))
+ return true;
- while (canTakeNextToken(mode, session) && !session.needsYield) {
- if (!isParsingFragment())
- m_sourceTracker.start(m_input.current(), m_tokenizer.get(), token());
+ if (!parsingFragment)
+ m_sourceTracker.startToken(m_input.current(), m_tokenizer);
- if (!m_tokenizer->nextToken(m_input.current(), token()))
- break;
+ auto token = m_tokenizer.nextToken(m_input.current());
+ if (!token)
+ return false;
- if (!isParsingFragment()) {
- m_sourceTracker.end(m_input.current(), m_tokenizer.get(), token());
+ if (!parsingFragment) {
+ m_sourceTracker.endToken(m_input.current(), m_tokenizer);
// We do not XSS filter innerHTML, which means we (intentionally) fail
// http/tests/security/xssAuditor/dom-write-innerHTML.html
- if (auto xssInfo = m_xssAuditor.filterToken(FilterTokenRequest(token(), m_sourceTracker, m_tokenizer->shouldAllowCDATA())))
+ if (auto xssInfo = m_xssAuditor.filterToken(FilterTokenRequest(*token, m_sourceTracker, m_tokenizer.shouldAllowCDATA())))
m_xssAuditorDelegate.didBlockScript(*xssInfo);
}
- constructTreeFromHTMLToken(token());
- ASSERT(token().isUninitialized());
- }
+ constructTreeFromHTMLToken(token);
+ } while (!isStopped());
+
+ return false;
+}
+
+void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
+{
+ ASSERT(!isStopped());
+ ASSERT(!isScheduledForResume());
+
+ // This is an attempt to check that this object is both attached to the Document and protected by something.
+ ASSERT(refCount() >= 2);
+
+ PumpSession session(m_pumpSessionNestingLevel, contextForParsingSession());
+
+ m_xssAuditor.init(document(), &m_xssAuditorDelegate);
+
+ bool shouldResume = pumpTokenizerLoop(mode, isParsingFragment(), session);
// Ensure we haven't been totally deref'ed after pumping. Any caller of this
// function should be holding a RefPtr to this to ensure we weren't deleted.
@@ -317,24 +284,22 @@ void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
if (isStopped())
return;
- if (session.needsYield)
+ if (shouldResume)
m_parserScheduler->scheduleForResume();
if (isWaitingForScripts()) {
- ASSERT(m_tokenizer->state() == HTMLTokenizer::DataState);
+ ASSERT(m_tokenizer.isInDataState());
if (!m_preloadScanner) {
m_preloadScanner = std::make_unique<HTMLPreloadScanner>(m_options, document()->url(), document()->deviceScaleFactor());
m_preloadScanner->appendToEnd(m_input.current());
}
- m_preloadScanner->scan(m_preloader.get(), document()->baseElementURL());
+ m_preloadScanner->scan(*m_preloader, *document());
}
-
- InspectorInstrumentation::didWriteHTML(cookie, m_input.current().currentLine().zeroBasedInt());
}
-void HTMLDocumentParser::constructTreeFromHTMLToken(HTMLToken& rawToken)
+void HTMLDocumentParser::constructTreeFromHTMLToken(HTMLTokenizer::TokenPtr& rawToken)
{
- AtomicHTMLToken token(rawToken);
+ AtomicHTMLToken token(*rawToken);
// We clear the rawToken in case constructTreeFromAtomicToken
// synchronously re-enters the parser. We don't clear the token immedately
@@ -346,63 +311,59 @@ void HTMLDocumentParser::constructTreeFromHTMLToken(HTMLToken& rawToken)
// FIXME: Stop clearing the rawToken once we start running the parser off
// the main thread or once we stop allowing synchronous JavaScript
// execution from parseAttribute.
- if (rawToken.type() != HTMLToken::Character)
- rawToken.clear();
-
- m_treeBuilder->constructTree(&token);
-
- if (!rawToken.isUninitialized()) {
- ASSERT(rawToken.type() == HTMLToken::Character);
+ if (rawToken->type() != HTMLToken::Character) {
+ // Clearing the TokenPtr makes sure we don't clear the HTMLToken a second time
+ // later when the TokenPtr is destroyed.
rawToken.clear();
}
+
+ m_treeBuilder->constructTree(WTFMove(token));
}
bool HTMLDocumentParser::hasInsertionPoint()
{
// FIXME: The wasCreatedByScript() branch here might not be fully correct.
- // Our model of the EOF character differs slightly from the one in
- // the spec because our treatment is uniform between network-sourced
- // and script-sourced input streams whereas the spec treats them
- // differently.
+ // Our model of the EOF character differs slightly from the one in the spec
+ // because our treatment is uniform between network-sourced and script-sourced
+ // input streams whereas the spec treats them differently.
return m_input.hasInsertionPoint() || (wasCreatedByScript() && !m_input.haveSeenEndOfFile());
}
-void HTMLDocumentParser::insert(const SegmentedString& source)
+void HTMLDocumentParser::insert(SegmentedString&& source)
{
if (isStopped())
return;
// pumpTokenizer can cause this parser to be detached from the Document,
// but we need to ensure it isn't deleted yet.
- Ref<HTMLDocumentParser> protect(*this);
+ Ref<HTMLDocumentParser> protectedThis(*this);
- SegmentedString excludedLineNumberSource(source);
- excludedLineNumberSource.setExcludeLineNumbers();
- m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource);
+ source.setExcludeLineNumbers();
+ m_input.insertAtCurrentInsertionPoint(WTFMove(source));
pumpTokenizerIfPossible(ForceSynchronous);
if (isWaitingForScripts()) {
// Check the document.write() output with a separate preload scanner as
// the main scanner can't deal with insertions.
- if (!m_insertionPreloadScanner) {
+ if (!m_insertionPreloadScanner)
m_insertionPreloadScanner = std::make_unique<HTMLPreloadScanner>(m_options, document()->url(), document()->deviceScaleFactor());
- }
m_insertionPreloadScanner->appendToEnd(source);
- m_insertionPreloadScanner->scan(m_preloader.get(), document()->baseElementURL());
+ m_insertionPreloadScanner->scan(*m_preloader, *document());
}
endIfDelayed();
}
-void HTMLDocumentParser::append(PassRefPtr<StringImpl> inputSource)
+void HTMLDocumentParser::append(RefPtr<StringImpl>&& inputSource)
{
if (isStopped())
return;
// pumpTokenizer can cause this parser to be detached from the Document,
// but we need to ensure it isn't deleted yet.
- Ref<HTMLDocumentParser> protect(*this);
- String source(inputSource);
+ Ref<HTMLDocumentParser> protectedThis(*this);
+
+ String source { WTFMove(inputSource) };
if (m_preloadScanner) {
if (m_input.current().isEmpty() && !isWaitingForScripts()) {
@@ -412,7 +373,7 @@ void HTMLDocumentParser::append(PassRefPtr<StringImpl> inputSource)
} else {
m_preloadScanner->appendToEnd(source);
if (isWaitingForScripts())
- m_preloadScanner->scan(m_preloader.get(), document()->baseElementURL());
+ m_preloadScanner->scan(*m_preloader, *document());
}
}
@@ -442,9 +403,7 @@ void HTMLDocumentParser::end()
void HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd()
{
ASSERT(isStopping());
- // FIXME: It may not be correct to disable this for the background parser.
- // That means hasInsertionPoint() may not be correct in some cases.
- ASSERT(!hasInsertionPoint() || m_haveBackgroundParser);
+ ASSERT(!hasInsertionPoint());
if (m_scriptRunner && !m_scriptRunner->executeScriptsWaitingForParsing())
return;
end();
@@ -492,18 +451,18 @@ void HTMLDocumentParser::finish()
bool HTMLDocumentParser::isExecutingScript() const
{
- if (!m_scriptRunner)
- return false;
- return m_scriptRunner->isExecutingScript();
+ return m_scriptRunner && m_scriptRunner->isExecutingScript();
}
TextPosition HTMLDocumentParser::textPosition() const
{
- const SegmentedString& currentString = m_input.current();
- OrdinalNumber line = currentString.currentLine();
- OrdinalNumber column = currentString.currentColumn();
+ auto& currentString = m_input.current();
+ return TextPosition(currentString.currentLine(), currentString.currentColumn());
+}
- return TextPosition(line, column);
+bool HTMLDocumentParser::shouldAssociateConsoleMessagesWithTextPosition() const
+{
+ return inPumpSession() && !isExecutingScript();
}
bool HTMLDocumentParser::isWaitingForScripts() const
@@ -513,7 +472,7 @@ bool HTMLDocumentParser::isWaitingForScripts() const
// The script runner will hold the script until its loaded and run. During
// any of this time, we want to count ourselves as "waiting for a script" and thus
// run the preload scanner, as well as delay completion of parsing.
- bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScript();
+ bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScriptWork();
bool scriptRunnerHasBlockingScript = m_scriptRunner && m_scriptRunner->hasParserBlockingScript();
// Since the parser is paused while a script runner has a blocking script, it should
// never be possible to end up with both objects holding a blocking script.
@@ -527,37 +486,45 @@ void HTMLDocumentParser::resumeParsingAfterScriptExecution()
ASSERT(!isExecutingScript());
ASSERT(!isWaitingForScripts());
+ // pumpTokenizer can cause this parser to be detached from the Document,
+ // but we need to ensure it isn't deleted yet.
+ Ref<HTMLDocumentParser> protectedThis(*this);
+
m_insertionPreloadScanner = nullptr;
pumpTokenizerIfPossible(AllowYield);
endIfDelayed();
}
-void HTMLDocumentParser::watchForLoad(CachedResource* cachedScript)
+void HTMLDocumentParser::watchForLoad(PendingScript& pendingScript)
{
- ASSERT(!cachedScript->isLoaded());
- // addClient would call notifyFinished if the load were complete.
+ ASSERT(!pendingScript.isLoaded());
+ // setClient would call notifyFinished if the load were complete.
// Callers do not expect to be re-entered from this call, so they should
- // not an already-loaded CachedResource.
- cachedScript->addClient(this);
+ // not an already-loaded PendingScript.
+ pendingScript.setClient(*this);
}
-void HTMLDocumentParser::stopWatchingForLoad(CachedResource* cachedScript)
+void HTMLDocumentParser::stopWatchingForLoad(PendingScript& pendingScript)
{
- cachedScript->removeClient(this);
+ pendingScript.clearClient();
}
-
+
void HTMLDocumentParser::appendCurrentInputStreamToPreloadScannerAndScan()
{
ASSERT(m_preloadScanner);
m_preloadScanner->appendToEnd(m_input.current());
- m_preloadScanner->scan(m_preloader.get(), document()->baseElementURL());
+ m_preloadScanner->scan(*m_preloader, *document());
}
-void HTMLDocumentParser::notifyFinished(CachedResource* cachedResource)
+void HTMLDocumentParser::notifyFinished(PendingScript& pendingScript)
{
// pumpTokenizer can cause this parser to be detached from the Document,
// but we need to ensure it isn't deleted yet.
- Ref<HTMLDocumentParser> protect(*this);
+ Ref<HTMLDocumentParser> protectedThis(*this);
+
+ // After Document parser is stopped or detached, the parser-inserted deferred script execution should be ignored.
+ if (isStopped())
+ return;
ASSERT(m_scriptRunner);
ASSERT(!isExecutingScript());
@@ -566,11 +533,16 @@ void HTMLDocumentParser::notifyFinished(CachedResource* cachedResource)
return;
}
- m_scriptRunner->executeScriptsWaitingForLoad(cachedResource);
+ m_scriptRunner->executeScriptsWaitingForLoad(pendingScript);
if (!isWaitingForScripts())
resumeParsingAfterScriptExecution();
}
+bool HTMLDocumentParser::hasScriptsWaitingForStylesheets() const
+{
+ return m_scriptRunner && m_scriptRunner->hasScriptsWaitingForStylesheets();
+}
+
void HTMLDocumentParser::executeScriptsWaitingForStylesheets()
{
// Document only calls this when the Document owns the DocumentParser
@@ -584,19 +556,19 @@ void HTMLDocumentParser::executeScriptsWaitingForStylesheets()
// pumpTokenizer can cause this parser to be detached from the Document,
// but we need to ensure it isn't deleted yet.
- Ref<HTMLDocumentParser> protect(*this);
+ Ref<HTMLDocumentParser> protectedThis(*this);
m_scriptRunner->executeScriptsWaitingForStylesheets();
if (!isWaitingForScripts())
resumeParsingAfterScriptExecution();
}
-void HTMLDocumentParser::parseDocumentFragment(const String& source, DocumentFragment& fragment, Element* contextElement, ParserContentPolicy parserContentPolicy)
+void HTMLDocumentParser::parseDocumentFragment(const String& source, DocumentFragment& fragment, Element& contextElement, ParserContentPolicy parserContentPolicy)
{
- RefPtr<HTMLDocumentParser> parser = HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy);
+ auto parser = create(fragment, contextElement, parserContentPolicy);
parser->insert(source); // Use insert() so that the parser will not yield.
parser->finish();
- ASSERT(!parser->processingData()); // Make sure we're done. <rdar://problem/3963151>
- parser->detach(); // Allows ~DocumentParser to assert it was detached before destruction.
+ ASSERT(!parser->processingData());
+ parser->detach();
}
void HTMLDocumentParser::suspendScheduledTasks()
diff --git a/Source/WebCore/html/parser/HTMLDocumentParser.h b/Source/WebCore/html/parser/HTMLDocumentParser.h
index 89d44960d..9a79d44c4 100644
--- a/Source/WebCore/html/parser/HTMLDocumentParser.h
+++ b/Source/WebCore/html/parser/HTMLDocumentParser.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2015 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,111 +24,89 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLDocumentParser_h
-#define HTMLDocumentParser_h
+#pragma once
-#include "CachedResourceClient.h"
-#include "FragmentScriptingPermission.h"
#include "HTMLInputStream.h"
-#include "HTMLParserOptions.h"
-#include "HTMLPreloadScanner.h"
#include "HTMLScriptRunnerHost.h"
#include "HTMLSourceTracker.h"
-#include "HTMLToken.h"
#include "HTMLTokenizer.h"
+#include "PendingScriptClient.h"
#include "ScriptableDocumentParser.h"
-#include "SegmentedString.h"
#include "XSSAuditor.h"
#include "XSSAuditorDelegate.h"
-#include <wtf/Deque.h>
-#include <wtf/WeakPtr.h>
-#include <wtf/text/TextPosition.h>
namespace WebCore {
-class BackgroundHTMLParser;
-class CompactHTMLToken;
-class Document;
class DocumentFragment;
+class Element;
class HTMLDocument;
class HTMLParserScheduler;
+class HTMLPreloadScanner;
class HTMLScriptRunner;
class HTMLTreeBuilder;
class HTMLResourcePreloader;
-class ScriptController;
-class ScriptSourceCode;
-
class PumpSession;
-class HTMLDocumentParser : public ScriptableDocumentParser, HTMLScriptRunnerHost, CachedResourceClient {
+class HTMLDocumentParser : public ScriptableDocumentParser, private HTMLScriptRunnerHost, private PendingScriptClient {
WTF_MAKE_FAST_ALLOCATED;
public:
- static PassRefPtr<HTMLDocumentParser> create(HTMLDocument& document)
- {
- return adoptRef(new HTMLDocumentParser(document));
- }
+ static Ref<HTMLDocumentParser> create(HTMLDocument&);
virtual ~HTMLDocumentParser();
- // Exposed for HTMLParserScheduler
- void resumeParsingAfterYield();
-
- static void parseDocumentFragment(const String&, DocumentFragment&, Element* contextElement, ParserContentPolicy = AllowScriptingContent);
-
- HTMLTokenizer* tokenizer() const { return m_tokenizer.get(); }
+ static void parseDocumentFragment(const String&, DocumentFragment&, Element& contextElement, ParserContentPolicy = AllowScriptingContent);
- virtual TextPosition textPosition() const override;
+ // For HTMLParserScheduler.
+ void resumeParsingAfterYield();
- virtual void suspendScheduledTasks() override;
- virtual void resumeScheduledTasks() override;
+ // For HTMLTreeBuilder.
+ HTMLTokenizer& tokenizer();
+ TextPosition textPosition() const final;
protected:
- virtual void insert(const SegmentedString&) override;
- virtual void append(PassRefPtr<StringImpl>) override;
- virtual void finish() override;
-
explicit HTMLDocumentParser(HTMLDocument&);
- HTMLDocumentParser(DocumentFragment&, Element* contextElement, ParserContentPolicy);
- HTMLTreeBuilder* treeBuilder() const { return m_treeBuilder.get(); }
+ void insert(SegmentedString&&) final;
+ void append(RefPtr<StringImpl>&&) override;
+ void finish() override;
- void forcePlaintextForTextDocument();
+ HTMLTreeBuilder& treeBuilder();
private:
- static PassRefPtr<HTMLDocumentParser> create(DocumentFragment& fragment, Element* contextElement, ParserContentPolicy parserContentPolicy)
- {
- return adoptRef(new HTMLDocumentParser(fragment, contextElement, parserContentPolicy));
- }
+ HTMLDocumentParser(DocumentFragment&, Element& contextElement, ParserContentPolicy);
+ static Ref<HTMLDocumentParser> create(DocumentFragment&, Element& contextElement, ParserContentPolicy);
// DocumentParser
- virtual void detach() override;
- virtual bool hasInsertionPoint() override;
- virtual bool processingData() const override;
- virtual void prepareToStopParsing() override;
- virtual void stopParsing() override;
- virtual bool isWaitingForScripts() const override;
- virtual bool isExecutingScript() const override;
- virtual void executeScriptsWaitingForStylesheets() override;
+ void detach() final;
+ bool hasInsertionPoint() final;
+ bool processingData() const final;
+ void prepareToStopParsing() final;
+ void stopParsing() final;
+ bool isWaitingForScripts() const override;
+ bool isExecutingScript() const final;
+ bool hasScriptsWaitingForStylesheets() const final;
+ void executeScriptsWaitingForStylesheets() final;
+ void suspendScheduledTasks() final;
+ void resumeScheduledTasks() final;
+
+ bool shouldAssociateConsoleMessagesWithTextPosition() const final;
// HTMLScriptRunnerHost
- virtual void watchForLoad(CachedResource*) override;
- virtual void stopWatchingForLoad(CachedResource*) override;
- virtual HTMLInputStream& inputStream() override { return m_input; }
- virtual bool hasPreloadScanner() const override { return m_preloadScanner.get(); }
- virtual void appendCurrentInputStreamToPreloadScannerAndScan() override;
+ void watchForLoad(PendingScript&) final;
+ void stopWatchingForLoad(PendingScript&) final;
+ HTMLInputStream& inputStream() final;
+ bool hasPreloadScanner() const final;
+ void appendCurrentInputStreamToPreloadScannerAndScan() final;
- // CachedResourceClient
- virtual void notifyFinished(CachedResource*) override;
+ // PendingScriptClient
+ void notifyFinished(PendingScript&) final;
Document* contextForParsingSession();
- enum SynchronousMode {
- AllowYield,
- ForceSynchronous,
- };
- bool canTakeNextToken(SynchronousMode, PumpSession&);
+ enum SynchronousMode { AllowYield, ForceSynchronous };
void pumpTokenizer(SynchronousMode);
+ bool pumpTokenizerLoop(SynchronousMode, bool parsingFragment, PumpSession&);
void pumpTokenizerIfPossible(SynchronousMode);
- void constructTreeFromHTMLToken(HTMLToken&);
+ void constructTreeFromHTMLToken(HTMLTokenizer::TokenPtr&);
void runScriptsForPausedTreeBuilder();
void resumeParsingAfterScriptExecution();
@@ -139,16 +118,13 @@ private:
bool isParsingFragment() const;
bool isScheduledForResume() const;
- bool inPumpSession() const { return m_pumpSessionNestingLevel > 0; }
- bool shouldDelayEnd() const { return inPumpSession() || isWaitingForScripts() || isScheduledForResume() || isExecutingScript(); }
-
- HTMLToken& token() { return *m_token.get(); }
+ bool inPumpSession() const;
+ bool shouldDelayEnd() const;
HTMLParserOptions m_options;
HTMLInputStream m_input;
- std::unique_ptr<HTMLToken> m_token;
- std::unique_ptr<HTMLTokenizer> m_tokenizer;
+ HTMLTokenizer m_tokenizer;
std::unique_ptr<HTMLScriptRunner> m_scriptRunner;
std::unique_ptr<HTMLTreeBuilder> m_treeBuilder;
std::unique_ptr<HTMLPreloadScanner> m_preloadScanner;
@@ -161,11 +137,29 @@ private:
std::unique_ptr<HTMLResourcePreloader> m_preloader;
- bool m_endWasDelayed;
- bool m_haveBackgroundParser;
- unsigned m_pumpSessionNestingLevel;
+ bool m_endWasDelayed { false };
+ unsigned m_pumpSessionNestingLevel { 0 };
};
+inline HTMLTokenizer& HTMLDocumentParser::tokenizer()
+{
+ return m_tokenizer;
+}
+
+inline HTMLInputStream& HTMLDocumentParser::inputStream()
+{
+ return m_input;
+}
+
+inline bool HTMLDocumentParser::hasPreloadScanner() const
+{
+ return m_preloadScanner.get();
+}
+
+inline HTMLTreeBuilder& HTMLDocumentParser::treeBuilder()
+{
+ ASSERT(m_treeBuilder);
+ return *m_treeBuilder;
}
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLElementStack.cpp b/Source/WebCore/html/parser/HTMLElementStack.cpp
index 2aaf6db92..705703efc 100644
--- a/Source/WebCore/html/parser/HTMLElementStack.cpp
+++ b/Source/WebCore/html/parser/HTMLElementStack.cpp
@@ -36,138 +36,118 @@ namespace WebCore {
using namespace HTMLNames;
-
namespace {
-inline bool isRootNode(HTMLStackItem* item)
-{
- return item->isDocumentFragmentNode()
- || item->hasTagName(htmlTag);
-}
-
-inline bool isScopeMarker(HTMLStackItem* item)
-{
- return item->hasTagName(appletTag)
- || item->hasTagName(captionTag)
- || item->hasTagName(marqueeTag)
- || item->hasTagName(objectTag)
- || isHTMLTableElement(item->node())
- || item->hasTagName(tdTag)
- || item->hasTagName(thTag)
- || item->hasTagName(MathMLNames::miTag)
- || item->hasTagName(MathMLNames::moTag)
- || item->hasTagName(MathMLNames::mnTag)
- || item->hasTagName(MathMLNames::msTag)
- || item->hasTagName(MathMLNames::mtextTag)
- || item->hasTagName(MathMLNames::annotation_xmlTag)
- || item->hasTagName(SVGNames::foreignObjectTag)
- || item->hasTagName(SVGNames::descTag)
- || item->hasTagName(SVGNames::titleTag)
-#if ENABLE(TEMPLATE_ELEMENT)
- || item->hasTagName(templateTag)
-#endif
+inline bool isRootNode(HTMLStackItem& item)
+{
+ return item.isDocumentFragment() || item.hasTagName(htmlTag);
+}
+
+inline bool isScopeMarker(HTMLStackItem& item)
+{
+ return item.hasTagName(appletTag)
+ || item.hasTagName(captionTag)
+ || item.hasTagName(marqueeTag)
+ || item.hasTagName(objectTag)
+ || is<HTMLTableElement>(item.node())
+ || item.hasTagName(tdTag)
+ || item.hasTagName(thTag)
+ || item.hasTagName(MathMLNames::miTag)
+ || item.hasTagName(MathMLNames::moTag)
+ || item.hasTagName(MathMLNames::mnTag)
+ || item.hasTagName(MathMLNames::msTag)
+ || item.hasTagName(MathMLNames::mtextTag)
+ || item.hasTagName(MathMLNames::annotation_xmlTag)
+ || item.hasTagName(SVGNames::foreignObjectTag)
+ || item.hasTagName(SVGNames::descTag)
+ || item.hasTagName(SVGNames::titleTag)
+ || item.hasTagName(templateTag)
|| isRootNode(item);
}
-inline bool isListItemScopeMarker(HTMLStackItem* item)
+inline bool isListItemScopeMarker(HTMLStackItem& item)
{
return isScopeMarker(item)
- || item->hasTagName(olTag)
- || item->hasTagName(ulTag);
+ || item.hasTagName(olTag)
+ || item.hasTagName(ulTag);
}
-inline bool isTableScopeMarker(HTMLStackItem* item)
+inline bool isTableScopeMarker(HTMLStackItem& item)
{
- return isHTMLTableElement(item->node())
-#if ENABLE(TEMPLATE_ELEMENT)
- || item->hasTagName(templateTag)
-#endif
+ return is<HTMLTableElement>(item.node())
+ || item.hasTagName(templateTag)
|| isRootNode(item);
}
-inline bool isTableBodyScopeMarker(HTMLStackItem* item)
+inline bool isTableBodyScopeMarker(HTMLStackItem& item)
{
- return item->hasTagName(tbodyTag)
- || item->hasTagName(tfootTag)
- || item->hasTagName(theadTag)
-#if ENABLE(TEMPLATE_ELEMENT)
- || item->hasTagName(templateTag)
-#endif
+ return item.hasTagName(tbodyTag)
+ || item.hasTagName(tfootTag)
+ || item.hasTagName(theadTag)
+ || item.hasTagName(templateTag)
|| isRootNode(item);
}
-inline bool isTableRowScopeMarker(HTMLStackItem* item)
+inline bool isTableRowScopeMarker(HTMLStackItem& item)
{
- return item->hasTagName(trTag)
-#if ENABLE(TEMPLATE_ELEMENT)
- || item->hasTagName(templateTag)
-#endif
+ return item.hasTagName(trTag)
+ || item.hasTagName(templateTag)
|| isRootNode(item);
}
-inline bool isForeignContentScopeMarker(HTMLStackItem* item)
+inline bool isForeignContentScopeMarker(HTMLStackItem& item)
{
return HTMLElementStack::isMathMLTextIntegrationPoint(item)
|| HTMLElementStack::isHTMLIntegrationPoint(item)
- || item->isInHTMLNamespace();
+ || isInHTMLNamespace(item);
}
-inline bool isButtonScopeMarker(HTMLStackItem* item)
+inline bool isButtonScopeMarker(HTMLStackItem& item)
{
return isScopeMarker(item)
- || item->hasTagName(buttonTag);
+ || item.hasTagName(buttonTag);
}
-inline bool isSelectScopeMarker(HTMLStackItem* item)
+inline bool isSelectScopeMarker(HTMLStackItem& item)
{
- return !isHTMLOptGroupElement(item->node()) && !isHTMLOptionElement(item->node());
+ return !is<HTMLOptGroupElement>(item.node()) && !is<HTMLOptionElement>(item.node());
}
}
-HTMLElementStack::ElementRecord::ElementRecord(PassRefPtr<HTMLStackItem> item, std::unique_ptr<ElementRecord> next)
- : m_item(item)
- , m_next(std::move(next))
+HTMLElementStack::ElementRecord::ElementRecord(Ref<HTMLStackItem>&& item, std::unique_ptr<ElementRecord> next)
+ : m_item(WTFMove(item))
+ , m_next(WTFMove(next))
{
- ASSERT(m_item);
}
HTMLElementStack::ElementRecord::~ElementRecord()
{
}
-void HTMLElementStack::ElementRecord::replaceElement(PassRefPtr<HTMLStackItem> item)
+void HTMLElementStack::ElementRecord::replaceElement(Ref<HTMLStackItem>&& item)
{
- ASSERT(item);
- ASSERT(!m_item || m_item->isElementNode());
+ ASSERT(m_item->isElement());
// FIXME: Should this call finishParsingChildren?
- m_item = item;
+ m_item = WTFMove(item);
}
-bool HTMLElementStack::ElementRecord::isAbove(ElementRecord* other) const
+bool HTMLElementStack::ElementRecord::isAbove(ElementRecord& other) const
{
- for (ElementRecord* below = next(); below; below = below->next()) {
- if (below == other)
+ for (auto* below = next(); below; below = below->next()) {
+ if (below == &other)
return true;
}
return false;
}
-HTMLElementStack::HTMLElementStack()
- : m_rootNode(0)
- , m_headElement(0)
- , m_bodyElement(0)
- , m_stackDepth(0)
-{
-}
-
HTMLElementStack::~HTMLElementStack()
{
}
bool HTMLElementStack::hasOnlyOneElement() const
{
- return !topRecord()->next();
+ return !topRecord().next();
}
bool HTMLElementStack::secondElementIsHTMLBodyElement() const
@@ -184,39 +164,39 @@ bool HTMLElementStack::secondElementIsHTMLBodyElement() const
void HTMLElementStack::popHTMLHeadElement()
{
- ASSERT(top() == m_headElement);
- m_headElement = 0;
+ ASSERT(&top() == m_headElement);
+ m_headElement = nullptr;
popCommon();
}
void HTMLElementStack::popHTMLBodyElement()
{
- ASSERT(top() == m_bodyElement);
- m_bodyElement = 0;
+ ASSERT(&top() == m_bodyElement);
+ m_bodyElement = nullptr;
popCommon();
}
void HTMLElementStack::popAll()
{
- m_rootNode = 0;
- m_headElement = 0;
- m_bodyElement = 0;
+ m_rootNode = nullptr;
+ m_headElement = nullptr;
+ m_bodyElement = nullptr;
m_stackDepth = 0;
while (m_top) {
- topNode()->finishParsingChildren();
+ topNode().finishParsingChildren();
m_top = m_top->releaseNext();
}
}
void HTMLElementStack::pop()
{
- ASSERT(!topStackItem()->hasTagName(HTMLNames::headTag));
+ ASSERT(!topStackItem().hasTagName(HTMLNames::headTag));
popCommon();
}
void HTMLElementStack::popUntil(const AtomicString& tagName)
{
- while (!topStackItem()->matchesHTMLTag(tagName)) {
+ while (!topStackItem().matchesHTMLTag(tagName)) {
// pop() will ASSERT if a <body>, <head> or <html> will be popped.
pop();
}
@@ -230,18 +210,18 @@ void HTMLElementStack::popUntilPopped(const AtomicString& tagName)
void HTMLElementStack::popUntilNumberedHeaderElementPopped()
{
- while (!topStackItem()->isNumberedHeaderElement())
+ while (!isNumberedHeaderElement(topStackItem()))
pop();
pop();
}
-void HTMLElementStack::popUntil(Element* element)
+void HTMLElementStack::popUntil(Element& element)
{
- while (top() != element)
+ while (&top() != &element)
pop();
}
-void HTMLElementStack::popUntilPopped(Element* element)
+void HTMLElementStack::popUntilPopped(Element& element)
{
popUntil(element);
pop();
@@ -269,34 +249,30 @@ void HTMLElementStack::popUntilTableRowScopeMarker()
}
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#mathml-text-integration-point
-bool HTMLElementStack::isMathMLTextIntegrationPoint(HTMLStackItem* item)
+bool HTMLElementStack::isMathMLTextIntegrationPoint(HTMLStackItem& item)
{
- if (!item->isElementNode())
- return false;
- return item->hasTagName(MathMLNames::miTag)
- || item->hasTagName(MathMLNames::moTag)
- || item->hasTagName(MathMLNames::mnTag)
- || item->hasTagName(MathMLNames::msTag)
- || item->hasTagName(MathMLNames::mtextTag);
+ return item.hasTagName(MathMLNames::miTag)
+ || item.hasTagName(MathMLNames::moTag)
+ || item.hasTagName(MathMLNames::mnTag)
+ || item.hasTagName(MathMLNames::msTag)
+ || item.hasTagName(MathMLNames::mtextTag);
}
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#html-integration-point
-bool HTMLElementStack::isHTMLIntegrationPoint(HTMLStackItem* item)
+bool HTMLElementStack::isHTMLIntegrationPoint(HTMLStackItem& item)
{
- if (!item->isElementNode())
- return false;
- if (item->hasTagName(MathMLNames::annotation_xmlTag)) {
- Attribute* encodingAttr = item->getAttributeItem(MathMLNames::encodingAttr);
+ if (item.hasTagName(MathMLNames::annotation_xmlTag)) {
+ const Attribute* encodingAttr = item.findAttribute(MathMLNames::encodingAttr);
if (encodingAttr) {
const String& encoding = encodingAttr->value();
- return equalIgnoringCase(encoding, "text/html")
- || equalIgnoringCase(encoding, "application/xhtml+xml");
+ return equalLettersIgnoringASCIICase(encoding, "text/html")
+ || equalLettersIgnoringASCIICase(encoding, "application/xhtml+xml");
}
return false;
}
- return item->hasTagName(SVGNames::foreignObjectTag)
- || item->hasTagName(SVGNames::descTag)
- || item->hasTagName(SVGNames::titleTag);
+ return item.hasTagName(SVGNames::foreignObjectTag)
+ || item.hasTagName(SVGNames::descTag)
+ || item.hasTagName(SVGNames::titleTag);
}
void HTMLElementStack::popUntilForeignContentScopeMarker()
@@ -305,81 +281,79 @@ void HTMLElementStack::popUntilForeignContentScopeMarker()
pop();
}
-void HTMLElementStack::pushRootNode(PassRefPtr<HTMLStackItem> rootItem)
+void HTMLElementStack::pushRootNode(Ref<HTMLStackItem>&& rootItem)
{
- ASSERT(rootItem->isDocumentFragmentNode());
- pushRootNodeCommon(rootItem);
+ ASSERT(rootItem->isDocumentFragment());
+ pushRootNodeCommon(WTFMove(rootItem));
}
-void HTMLElementStack::pushHTMLHtmlElement(PassRefPtr<HTMLStackItem> item)
+void HTMLElementStack::pushHTMLHtmlElement(Ref<HTMLStackItem>&& item)
{
ASSERT(item->hasTagName(HTMLNames::htmlTag));
- pushRootNodeCommon(item);
+ pushRootNodeCommon(WTFMove(item));
}
-void HTMLElementStack::pushRootNodeCommon(PassRefPtr<HTMLStackItem> rootItem)
+void HTMLElementStack::pushRootNodeCommon(Ref<HTMLStackItem>&& rootItem)
{
ASSERT(!m_top);
ASSERT(!m_rootNode);
- m_rootNode = rootItem->node();
- pushCommon(rootItem);
+ m_rootNode = &rootItem->node();
+ pushCommon(WTFMove(rootItem));
}
-void HTMLElementStack::pushHTMLHeadElement(PassRefPtr<HTMLStackItem> item)
+void HTMLElementStack::pushHTMLHeadElement(Ref<HTMLStackItem>&& item)
{
ASSERT(item->hasTagName(HTMLNames::headTag));
ASSERT(!m_headElement);
- m_headElement = item->element();
- pushCommon(item);
+ m_headElement = &item->element();
+ pushCommon(WTFMove(item));
}
-void HTMLElementStack::pushHTMLBodyElement(PassRefPtr<HTMLStackItem> item)
+void HTMLElementStack::pushHTMLBodyElement(Ref<HTMLStackItem>&& item)
{
ASSERT(item->hasTagName(HTMLNames::bodyTag));
ASSERT(!m_bodyElement);
- m_bodyElement = item->element();
- pushCommon(item);
+ m_bodyElement = &item->element();
+ pushCommon(WTFMove(item));
}
-void HTMLElementStack::push(PassRefPtr<HTMLStackItem> item)
+void HTMLElementStack::push(Ref<HTMLStackItem>&& item)
{
ASSERT(!item->hasTagName(HTMLNames::htmlTag));
ASSERT(!item->hasTagName(HTMLNames::headTag));
ASSERT(!item->hasTagName(HTMLNames::bodyTag));
ASSERT(m_rootNode);
- pushCommon(item);
+ pushCommon(WTFMove(item));
}
-void HTMLElementStack::insertAbove(PassRefPtr<HTMLStackItem> item, ElementRecord* recordBelow)
+void HTMLElementStack::insertAbove(Ref<HTMLStackItem>&& item, ElementRecord& recordBelow)
{
- ASSERT(item);
- ASSERT(recordBelow);
ASSERT(m_top);
ASSERT(!item->hasTagName(HTMLNames::htmlTag));
ASSERT(!item->hasTagName(HTMLNames::headTag));
ASSERT(!item->hasTagName(HTMLNames::bodyTag));
ASSERT(m_rootNode);
- if (recordBelow == m_top.get()) {
- push(item);
+ if (&recordBelow == m_top.get()) {
+ push(item.copyRef());
return;
}
- for (ElementRecord* recordAbove = m_top.get(); recordAbove; recordAbove = recordAbove->next()) {
- if (recordAbove->next() != recordBelow)
+ for (auto* recordAbove = m_top.get(); recordAbove; recordAbove = recordAbove->next()) {
+ if (recordAbove->next() != &recordBelow)
continue;
- m_stackDepth++;
- recordAbove->setNext(std::make_unique<ElementRecord>(item, recordAbove->releaseNext()));
- recordAbove->next()->element()->beginParsingChildren();
+ ++m_stackDepth;
+ recordAbove->setNext(std::make_unique<ElementRecord>(WTFMove(item), recordAbove->releaseNext()));
+ recordAbove->next()->element().beginParsingChildren();
return;
}
ASSERT_NOT_REACHED();
}
-HTMLElementStack::ElementRecord* HTMLElementStack::topRecord() const
+auto HTMLElementStack::topRecord() const -> ElementRecord&
{
ASSERT(m_top);
- return m_top.get();
+ return *m_top;
}
HTMLStackItem* HTMLElementStack::oneBelowTop() const
@@ -387,51 +361,51 @@ HTMLStackItem* HTMLElementStack::oneBelowTop() const
// We should never call this if there are fewer than 2 elements on the stack.
ASSERT(m_top);
ASSERT(m_top->next());
- if (m_top->next()->stackItem()->isElementNode())
- return m_top->next()->stackItem().get();
- return 0;
+ if (m_top->next()->stackItem().isElement())
+ return &m_top->next()->stackItem();
+ return nullptr;
}
-void HTMLElementStack::removeHTMLHeadElement(Element* element)
+void HTMLElementStack::removeHTMLHeadElement(Element& element)
{
- ASSERT(m_headElement == element);
- if (m_top->element() == element) {
+ ASSERT(m_headElement == &element);
+ if (&m_top->element() == &element) {
popHTMLHeadElement();
return;
}
- m_headElement = 0;
+ m_headElement = nullptr;
removeNonTopCommon(element);
}
-void HTMLElementStack::remove(Element* element)
+void HTMLElementStack::remove(Element& element)
{
- ASSERT(!element->hasTagName(HTMLNames::headTag));
- if (m_top->element() == element) {
+ ASSERT(!element.hasTagName(HTMLNames::headTag));
+ if (&m_top->element() == &element) {
pop();
return;
}
removeNonTopCommon(element);
}
-HTMLElementStack::ElementRecord* HTMLElementStack::find(Element* element) const
+auto HTMLElementStack::find(Element& element) const -> ElementRecord*
{
- for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
- if (pos->node() == element)
- return pos;
+ for (auto* record = m_top.get(); record; record = record->next()) {
+ if (&record->node() == &element)
+ return record;
}
- return 0;
+ return nullptr;
}
-HTMLElementStack::ElementRecord* HTMLElementStack::topmost(const AtomicString& tagName) const
+auto HTMLElementStack::topmost(const AtomicString& tagName) const -> ElementRecord*
{
- for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
- if (pos->stackItem()->matchesHTMLTag(tagName))
- return pos;
+ for (auto* record = m_top.get(); record; record = record->next()) {
+ if (record->stackItem().matchesHTMLTag(tagName))
+ return record;
}
- return 0;
+ return nullptr;
}
-bool HTMLElementStack::contains(Element* element) const
+bool HTMLElementStack::contains(Element& element) const
{
return !!find(element);
}
@@ -441,12 +415,11 @@ bool HTMLElementStack::contains(const AtomicString& tagName) const
return !!topmost(tagName);
}
-template <bool isMarker(HTMLStackItem*)>
-bool inScopeCommon(HTMLElementStack::ElementRecord* top, const AtomicString& targetTag)
+template <bool isMarker(HTMLStackItem&)> bool inScopeCommon(HTMLElementStack::ElementRecord* top, const AtomicString& targetTag)
{
- for (HTMLElementStack::ElementRecord* pos = top; pos; pos = pos->next()) {
- HTMLStackItem* item = pos->stackItem().get();
- if (item->matchesHTMLTag(targetTag))
+ for (auto* record = top; record; record = record->next()) {
+ auto& item = record->stackItem();
+ if (item.matchesHTMLTag(targetTag))
return true;
if (isMarker(item))
return false;
@@ -457,9 +430,9 @@ bool inScopeCommon(HTMLElementStack::ElementRecord* top, const AtomicString& tar
bool HTMLElementStack::hasNumberedHeaderElementInScope() const
{
- for (ElementRecord* record = m_top.get(); record; record = record->next()) {
- HTMLStackItem* item = record->stackItem().get();
- if (item->isNumberedHeaderElement())
+ for (auto* record = m_top.get(); record; record = record->next()) {
+ auto& item = record->stackItem();
+ if (isNumberedHeaderElement(item))
return true;
if (isScopeMarker(item))
return false;
@@ -468,11 +441,11 @@ bool HTMLElementStack::hasNumberedHeaderElementInScope() const
return false;
}
-bool HTMLElementStack::inScope(Element* targetElement) const
+bool HTMLElementStack::inScope(Element& targetElement) const
{
- for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
- HTMLStackItem* item = pos->stackItem().get();
- if (item->node() == targetElement)
+ for (auto* record = m_top.get(); record; record = record->next()) {
+ auto& item = record->stackItem();
+ if (&item.node() == &targetElement)
return true;
if (isScopeMarker(item))
return false;
@@ -531,93 +504,91 @@ bool HTMLElementStack::inSelectScope(const QualifiedName& tagName) const
return inSelectScope(tagName.localName());
}
-#if ENABLE(TEMPLATE_ELEMENT)
bool HTMLElementStack::hasTemplateInHTMLScope() const
{
return inScopeCommon<isRootNode>(m_top.get(), templateTag.localName());
}
-#endif
-Element* HTMLElementStack::htmlElement() const
+Element& HTMLElementStack::htmlElement() const
{
- ASSERT(m_rootNode);
- return toElement(m_rootNode);
+ return downcast<Element>(rootNode());
}
-Element* HTMLElementStack::headElement() const
+Element& HTMLElementStack::headElement() const
{
ASSERT(m_headElement);
- return m_headElement;
+ return *m_headElement;
}
-Element* HTMLElementStack::bodyElement() const
+Element& HTMLElementStack::bodyElement() const
{
ASSERT(m_bodyElement);
- return m_bodyElement;
+ return *m_bodyElement;
}
-ContainerNode* HTMLElementStack::rootNode() const
+ContainerNode& HTMLElementStack::rootNode() const
{
ASSERT(m_rootNode);
- return m_rootNode;
+ return *m_rootNode;
}
-void HTMLElementStack::pushCommon(PassRefPtr<HTMLStackItem> item)
+void HTMLElementStack::pushCommon(Ref<HTMLStackItem>&& item)
{
ASSERT(m_rootNode);
- m_stackDepth++;
- m_top = std::make_unique<ElementRecord>(item, std::move(m_top));
+ ++m_stackDepth;
+ m_top = std::make_unique<ElementRecord>(WTFMove(item), WTFMove(m_top));
}
void HTMLElementStack::popCommon()
{
- ASSERT(!topStackItem()->hasTagName(HTMLNames::htmlTag));
- ASSERT(!topStackItem()->hasTagName(HTMLNames::headTag) || !m_headElement);
- ASSERT(!topStackItem()->hasTagName(HTMLNames::bodyTag) || !m_bodyElement);
- top()->finishParsingChildren();
+ ASSERT(!topStackItem().hasTagName(HTMLNames::htmlTag));
+ ASSERT(!topStackItem().hasTagName(HTMLNames::headTag) || !m_headElement);
+ ASSERT(!topStackItem().hasTagName(HTMLNames::bodyTag) || !m_bodyElement);
+
+ top().finishParsingChildren();
m_top = m_top->releaseNext();
- m_stackDepth--;
+ --m_stackDepth;
}
-void HTMLElementStack::removeNonTopCommon(Element* element)
+void HTMLElementStack::removeNonTopCommon(Element& element)
{
- ASSERT(!element->hasTagName(HTMLNames::htmlTag));
- ASSERT(!element->hasTagName(HTMLNames::bodyTag));
- ASSERT(top() != element);
- for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
- if (pos->next()->element() == element) {
+ ASSERT(!element.hasTagName(HTMLNames::htmlTag));
+ ASSERT(!element.hasTagName(HTMLNames::bodyTag));
+ ASSERT(&top() != &element);
+ for (auto* record = m_top.get(); record; record = record->next()) {
+ if (&record->next()->element() == &element) {
// FIXME: Is it OK to call finishParsingChildren()
// when the children aren't actually finished?
- element->finishParsingChildren();
- pos->setNext(pos->next()->releaseNext());
- m_stackDepth--;
+ element.finishParsingChildren();
+ record->setNext(record->next()->releaseNext());
+ --m_stackDepth;
return;
}
}
ASSERT_NOT_REACHED();
}
-HTMLElementStack::ElementRecord* HTMLElementStack::furthestBlockForFormattingElement(Element* formattingElement) const
+auto HTMLElementStack::furthestBlockForFormattingElement(Element& formattingElement) const -> ElementRecord*
{
- ElementRecord* furthestBlock = 0;
- for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) {
- if (pos->element() == formattingElement)
+ ElementRecord* furthestBlock = nullptr;
+ for (auto* record = m_top.get(); record; record = record->next()) {
+ if (&record->element() == &formattingElement)
return furthestBlock;
- if (pos->stackItem()->isSpecialNode())
- furthestBlock = pos;
+ if (isSpecialNode(record->stackItem()))
+ furthestBlock = record;
}
ASSERT_NOT_REACHED();
- return 0;
+ return nullptr;
}
-#ifndef NDEBUG
+#if ENABLE(TREE_DEBUGGING)
void HTMLElementStack::show()
{
- for (ElementRecord* record = m_top.get(); record; record = record->next())
- record->element()->showNode();
+ for (auto* record = m_top.get(); record; record = record->next())
+ record->element().showNode();
}
#endif
diff --git a/Source/WebCore/html/parser/HTMLElementStack.h b/Source/WebCore/html/parser/HTMLElementStack.h
index a2c4f54de..a32d2f55e 100644
--- a/Source/WebCore/html/parser/HTMLElementStack.h
+++ b/Source/WebCore/html/parser/HTMLElementStack.h
@@ -24,8 +24,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLElementStack_h
-#define HTMLElementStack_h
+#pragma once
#include "HTMLStackItem.h"
#include <wtf/Forward.h>
@@ -35,7 +34,6 @@
namespace WebCore {
class ContainerNode;
-class DocumentFragment;
class Element;
class QualifiedName;
@@ -44,31 +42,34 @@ class QualifiedName;
class HTMLElementStack {
WTF_MAKE_NONCOPYABLE(HTMLElementStack); WTF_MAKE_FAST_ALLOCATED;
public:
- HTMLElementStack();
+ HTMLElementStack() = default;
~HTMLElementStack();
class ElementRecord {
WTF_MAKE_NONCOPYABLE(ElementRecord); WTF_MAKE_FAST_ALLOCATED;
public:
- ElementRecord(PassRefPtr<HTMLStackItem>, std::unique_ptr<ElementRecord>);
+ ElementRecord(Ref<HTMLStackItem>&&, std::unique_ptr<ElementRecord>);
~ElementRecord();
- Element* element() const { return m_item->element(); }
- ContainerNode* node() const { return m_item->node(); }
+ Element& element() const { return m_item->element(); }
+ ContainerNode& node() const { return m_item->node(); }
const AtomicString& namespaceURI() const { return m_item->namespaceURI(); }
- PassRefPtr<HTMLStackItem> stackItem() const { return m_item; }
- void replaceElement(PassRefPtr<HTMLStackItem>);
+ HTMLStackItem& stackItem() { return m_item.get(); }
+ const HTMLStackItem& stackItem() const { return m_item.get(); }
- bool isAbove(ElementRecord*) const;
+ void replaceElement(Ref<HTMLStackItem>&&);
+
+ bool isAbove(ElementRecord&) const;
ElementRecord* next() const { return m_next.get(); }
+
private:
friend class HTMLElementStack;
- std::unique_ptr<ElementRecord> releaseNext() { return std::move(m_next); }
- void setNext(std::unique_ptr<ElementRecord> next) { m_next = std::move(next); }
+ std::unique_ptr<ElementRecord> releaseNext() { return WTFMove(m_next); }
+ void setNext(std::unique_ptr<ElementRecord> next) { m_next = WTFMove(next); }
- RefPtr<HTMLStackItem> m_item;
+ Ref<HTMLStackItem> m_item;
std::unique_ptr<ElementRecord> m_next;
};
@@ -76,45 +77,42 @@ public:
// Inlining this function is a (small) performance win on the parsing
// benchmark.
- Element* top() const
+ Element& top() const
{
- ASSERT(m_top->element());
return m_top->element();
}
- ContainerNode* topNode() const
+ ContainerNode& topNode() const
{
- ASSERT(m_top->node());
return m_top->node();
}
- HTMLStackItem* topStackItem() const
+ HTMLStackItem& topStackItem() const
{
- ASSERT(m_top->stackItem());
- return m_top->stackItem().get();
+ return m_top->stackItem();
}
HTMLStackItem* oneBelowTop() const;
- ElementRecord* topRecord() const;
- ElementRecord* find(Element*) const;
- ElementRecord* furthestBlockForFormattingElement(Element*) const;
+ ElementRecord& topRecord() const;
+ ElementRecord* find(Element&) const;
+ ElementRecord* furthestBlockForFormattingElement(Element&) const;
ElementRecord* topmost(const AtomicString& tagName) const;
- void insertAbove(PassRefPtr<HTMLStackItem>, ElementRecord*);
+ void insertAbove(Ref<HTMLStackItem>&&, ElementRecord&);
- void push(PassRefPtr<HTMLStackItem>);
- void pushRootNode(PassRefPtr<HTMLStackItem>);
- void pushHTMLHtmlElement(PassRefPtr<HTMLStackItem>);
- void pushHTMLHeadElement(PassRefPtr<HTMLStackItem>);
- void pushHTMLBodyElement(PassRefPtr<HTMLStackItem>);
+ void push(Ref<HTMLStackItem>&&);
+ void pushRootNode(Ref<HTMLStackItem>&&);
+ void pushHTMLHtmlElement(Ref<HTMLStackItem>&&);
+ void pushHTMLHeadElement(Ref<HTMLStackItem>&&);
+ void pushHTMLBodyElement(Ref<HTMLStackItem>&&);
void pop();
void popUntil(const AtomicString& tagName);
- void popUntil(Element*);
+ void popUntil(Element&);
void popUntilPopped(const AtomicString& tagName);
void popUntilPopped(const QualifiedName& tagName) { popUntilPopped(tagName.localName()); }
- void popUntilPopped(Element*);
+ void popUntilPopped(Element&);
void popUntilNumberedHeaderElementPopped();
void popUntilTableScopeMarker(); // "clear the stack back to a table context" in the spec.
void popUntilTableBodyScopeMarker(); // "clear the stack back to a table body context" in the spec.
@@ -124,16 +122,16 @@ public:
void popHTMLBodyElement();
void popAll();
- static bool isMathMLTextIntegrationPoint(HTMLStackItem*);
- static bool isHTMLIntegrationPoint(HTMLStackItem*);
+ static bool isMathMLTextIntegrationPoint(HTMLStackItem&);
+ static bool isHTMLIntegrationPoint(HTMLStackItem&);
- void remove(Element*);
- void removeHTMLHeadElement(Element*);
+ void remove(Element&);
+ void removeHTMLHeadElement(Element&);
- bool contains(Element*) const;
+ bool contains(Element&) const;
bool contains(const AtomicString& tagName) const;
- bool inScope(Element*) const;
+ bool inScope(Element&) const;
bool inScope(const AtomicString& tagName) const;
bool inScope(const QualifiedName&) const;
bool inListItemScope(const AtomicString& tagName) const;
@@ -149,24 +147,22 @@ public:
bool hasOnlyOneElement() const;
bool secondElementIsHTMLBodyElement() const;
-#if ENABLE(TEMPLATE_ELEMENT)
bool hasTemplateInHTMLScope() const;
-#endif
- Element* htmlElement() const;
- Element* headElement() const;
- Element* bodyElement() const;
-
- ContainerNode* rootNode() const;
+ Element& htmlElement() const;
+ Element& headElement() const;
+ Element& bodyElement() const;
+
+ ContainerNode& rootNode() const;
-#ifndef NDEBUG
+#if ENABLE(TREE_DEBUGGING)
void show();
#endif
private:
- void pushCommon(PassRefPtr<HTMLStackItem>);
- void pushRootNodeCommon(PassRefPtr<HTMLStackItem>);
+ void pushCommon(Ref<HTMLStackItem>&&);
+ void pushRootNodeCommon(Ref<HTMLStackItem>&&);
void popCommon();
- void removeNonTopCommon(Element*);
+ void removeNonTopCommon(Element&);
std::unique_ptr<ElementRecord> m_top;
@@ -175,12 +171,10 @@ private:
// FIXME: We don't currently require type-specific information about
// these elements so we haven't yet bothered to plumb the types all the
// way down through createElement, etc.
- ContainerNode* m_rootNode;
- Element* m_headElement;
- Element* m_bodyElement;
- unsigned m_stackDepth;
+ ContainerNode* m_rootNode { nullptr };
+ Element* m_headElement { nullptr };
+ Element* m_bodyElement { nullptr };
+ unsigned m_stackDepth { 0 };
};
} // namespace WebCore
-
-#endif // HTMLElementStack_h
diff --git a/Source/WebCore/html/parser/HTMLEntityParser.cpp b/Source/WebCore/html/parser/HTMLEntityParser.cpp
index 8d2177fd2..98503d9d1 100644
--- a/Source/WebCore/html/parser/HTMLEntityParser.cpp
+++ b/Source/WebCore/html/parser/HTMLEntityParser.cpp
@@ -32,8 +32,7 @@
#include "HTMLEntitySearch.h"
#include "HTMLEntityTable.h"
#include <wtf/text/StringBuilder.h>
-
-using namespace WTF;
+#include <wtf/unicode/CharacterNames.h>
namespace WebCore {
@@ -44,43 +43,30 @@ static const UChar windowsLatin1ExtensionArray[32] = {
0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x009D, 0x017E, 0x0178, // 98-9F
};
-static inline bool isAlphaNumeric(UChar cc)
-{
- return (cc >= '0' && cc <= '9') || (cc >= 'a' && cc <= 'z') || (cc >= 'A' && cc <= 'Z');
-}
-
class HTMLEntityParser {
public:
- inline static UChar adjustEntity(UChar32 value)
+ static UChar32 legalEntityFor(UChar32 value)
{
- if ((value & ~0x1F) != 0x0080)
+ if (value <= 0 || value > UCHAR_MAX_VALUE || U_IS_SURROGATE(value))
+ return replacementCharacter;
+ if ((value & ~0x1F) != 0x80)
return value;
return windowsLatin1ExtensionArray[value - 0x80];
}
- inline static UChar32 legalEntityFor(UChar32 value)
- {
- // FIXME: A number of specific entity values generate parse errors.
- if (!value || value > 0x10FFFF || (value >= 0xD800 && value <= 0xDFFF))
- return 0xFFFD;
- if (U_IS_BMP(value))
- return adjustEntity(value);
- return value;
- }
-
- inline static bool acceptMalformed() { return true; }
+ static bool acceptMalformed() { return true; }
- inline static bool consumeNamedEntity(SegmentedString& source, StringBuilder& decodedEntity, bool& notEnoughCharacters, UChar additionalAllowedCharacter, UChar& cc)
+ static bool consumeNamedEntity(SegmentedString& source, StringBuilder& decodedEntity, bool& notEnoughCharacters, UChar additionalAllowedCharacter, UChar& cc)
{
StringBuilder consumedCharacters;
HTMLEntitySearch entitySearch;
while (!source.isEmpty()) {
- cc = source.currentChar();
+ cc = source.currentCharacter();
entitySearch.advance(cc);
if (!entitySearch.isEntityPrefix())
break;
consumedCharacters.append(cc);
- source.advanceAndASSERT(cc);
+ source.advancePastNonNewline();
}
notEnoughCharacters = source.isEmpty();
if (notEnoughCharacters) {
@@ -102,17 +88,17 @@ public:
const int length = entitySearch.mostRecentMatch()->length;
const LChar* reference = entitySearch.mostRecentMatch()->entity;
for (int i = 0; i < length; ++i) {
- cc = source.currentChar();
+ cc = source.currentCharacter();
ASSERT_UNUSED(reference, cc == *reference++);
consumedCharacters.append(cc);
- source.advanceAndASSERT(cc);
+ source.advancePastNonNewline();
ASSERT(!source.isEmpty());
}
- cc = source.currentChar();
+ cc = source.currentCharacter();
}
if (entitySearch.mostRecentMatch()->lastCharacter() == ';'
|| !additionalAllowedCharacter
- || !(isAlphaNumeric(cc) || cc == '=')) {
+ || !(isASCIIAlphanumeric(cc) || cc == '=')) {
decodedEntity.append(entitySearch.mostRecentMatch()->firstValue);
if (entitySearch.mostRecentMatch()->secondValue)
decodedEntity.append(entitySearch.mostRecentMatch()->secondValue);
diff --git a/Source/WebCore/html/parser/HTMLEntityParser.h b/Source/WebCore/html/parser/HTMLEntityParser.h
index 3f92eae2f..7d79224c6 100644
--- a/Source/WebCore/html/parser/HTMLEntityParser.h
+++ b/Source/WebCore/html/parser/HTMLEntityParser.h
@@ -24,8 +24,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLEntityParser_h
-#define HTMLEntityParser_h
+#pragma once
#include "SegmentedString.h"
@@ -36,6 +35,4 @@ bool consumeHTMLEntity(SegmentedString&, StringBuilder& decodedEntity, bool& not
// Used by the XML parser. Not suitable for use in HTML parsing. Use consumeHTMLEntity instead.
size_t decodeNamedEntityToUCharArray(const char*, UChar result[4]);
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLEntitySearch.h b/Source/WebCore/html/parser/HTMLEntitySearch.h
index 0cb5920d8..dbc588986 100644
--- a/Source/WebCore/html/parser/HTMLEntitySearch.h
+++ b/Source/WebCore/html/parser/HTMLEntitySearch.h
@@ -23,8 +23,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLEntitySearch_h
-#define HTMLEntitySearch_h
+#pragma once
#include <wtf/text/WTFString.h>
@@ -67,6 +66,4 @@ private:
const HTMLEntityTableEntry* m_last;
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLEntityTable.h b/Source/WebCore/html/parser/HTMLEntityTable.h
index 04fc5d7a5..4c42b1761 100644
--- a/Source/WebCore/html/parser/HTMLEntityTable.h
+++ b/Source/WebCore/html/parser/HTMLEntityTable.h
@@ -23,8 +23,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLEntityTable_h
-#define HTMLEntityTable_h
+#pragma once
#include <wtf/text/WTFString.h>
@@ -48,6 +47,4 @@ public:
static const HTMLEntityTableEntry* lastEntryStartingWith(UChar);
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLFormattingElementList.cpp b/Source/WebCore/html/parser/HTMLFormattingElementList.cpp
index f38a9384e..d35101b49 100644
--- a/Source/WebCore/html/parser/HTMLFormattingElementList.cpp
+++ b/Source/WebCore/html/parser/HTMLFormattingElementList.cpp
@@ -26,8 +26,6 @@
#include "config.h"
#include "HTMLFormattingElementList.h"
-#include "NotImplemented.h"
-
#ifndef NDEBUG
#include <stdio.h>
#endif
@@ -52,59 +50,59 @@ Element* HTMLFormattingElementList::closestElementInScopeWithName(const AtomicSt
for (unsigned i = 1; i <= m_entries.size(); ++i) {
const Entry& entry = m_entries[m_entries.size() - i];
if (entry.isMarker())
- return 0;
+ return nullptr;
if (entry.stackItem()->matchesHTMLTag(targetName))
- return entry.element();
+ return &entry.element();
}
- return 0;
+ return nullptr;
}
-bool HTMLFormattingElementList::contains(Element* element)
+bool HTMLFormattingElementList::contains(Element& element)
{
return !!find(element);
}
-HTMLFormattingElementList::Entry* HTMLFormattingElementList::find(Element* element)
+auto HTMLFormattingElementList::find(Element& element) -> Entry*
{
- size_t index = m_entries.reverseFind(element);
+ size_t index = m_entries.reverseFind(&element);
if (index != notFound) {
// This is somewhat of a hack, and is why this method can't be const.
return &m_entries[index];
}
- return 0;
+ return nullptr;
}
-HTMLFormattingElementList::Bookmark HTMLFormattingElementList::bookmarkFor(Element* element)
+auto HTMLFormattingElementList::bookmarkFor(Element& element) -> Bookmark
{
- size_t index = m_entries.reverseFind(element);
+ size_t index = m_entries.reverseFind(&element);
ASSERT(index != notFound);
- return Bookmark(&at(index));
+ return Bookmark(at(index));
}
-void HTMLFormattingElementList::swapTo(Element* oldElement, PassRefPtr<HTMLStackItem> newItem, const Bookmark& bookmark)
+void HTMLFormattingElementList::swapTo(Element& oldElement, Ref<HTMLStackItem>&& newItem, const Bookmark& bookmark)
{
ASSERT(contains(oldElement));
ASSERT(!contains(newItem->element()));
if (!bookmark.hasBeenMoved()) {
- ASSERT(bookmark.mark()->element() == oldElement);
- bookmark.mark()->replaceElement(newItem);
+ ASSERT(&bookmark.mark().element() == &oldElement);
+ bookmark.mark().replaceElement(newItem.copyRef());
return;
}
- size_t index = bookmark.mark() - first();
+ size_t index = &bookmark.mark() - &first();
ASSERT_WITH_SECURITY_IMPLICATION(index < size());
- m_entries.insert(index + 1, newItem);
+ m_entries.insert(index + 1, WTFMove(newItem));
remove(oldElement);
}
-void HTMLFormattingElementList::append(PassRefPtr<HTMLStackItem> item)
+void HTMLFormattingElementList::append(Ref<HTMLStackItem>&& item)
{
- ensureNoahsArkCondition(item.get());
- m_entries.append(item);
+ ensureNoahsArkCondition(item);
+ m_entries.append(WTFMove(item));
}
-void HTMLFormattingElementList::remove(Element* element)
+void HTMLFormattingElementList::remove(Element& element)
{
- size_t index = m_entries.reverseFind(element);
+ size_t index = m_entries.reverseFind(&element);
if (index != notFound)
m_entries.remove(index);
}
@@ -125,7 +123,7 @@ void HTMLFormattingElementList::clearToLastMarker()
}
}
-void HTMLFormattingElementList::tryToEnsureNoahsArkConditionQuickly(HTMLStackItem* newItem, Vector<HTMLStackItem*>& remainingCandidates)
+void HTMLFormattingElementList::tryToEnsureNoahsArkConditionQuickly(HTMLStackItem& newItem, Vector<HTMLStackItem*>& remainingCandidates)
{
ASSERT(remainingCandidates.isEmpty());
@@ -136,7 +134,7 @@ void HTMLFormattingElementList::tryToEnsureNoahsArkConditionQuickly(HTMLStackIte
// of a quickly ensuring the condition.
Vector<HTMLStackItem*, 10> candidates;
- size_t newItemAttributeCount = newItem->attributes().size();
+ size_t newItemAttributeCount = newItem.attributes().size();
for (size_t i = m_entries.size(); i; ) {
--i;
@@ -145,8 +143,8 @@ void HTMLFormattingElementList::tryToEnsureNoahsArkConditionQuickly(HTMLStackIte
break;
// Quickly reject obviously non-matching candidates.
- HTMLStackItem* candidate = entry.stackItem().get();
- if (newItem->localName() != candidate->localName() || newItem->namespaceURI() != candidate->namespaceURI())
+ HTMLStackItem* candidate = entry.stackItem();
+ if (newItem.localName() != candidate->localName() || newItem.namespaceURI() != candidate->namespaceURI())
continue;
if (candidate->attributes().size() != newItemAttributeCount)
continue;
@@ -160,7 +158,7 @@ void HTMLFormattingElementList::tryToEnsureNoahsArkConditionQuickly(HTMLStackIte
remainingCandidates.appendVector(candidates);
}
-void HTMLFormattingElementList::ensureNoahsArkCondition(HTMLStackItem* newItem)
+void HTMLFormattingElementList::ensureNoahsArkCondition(HTMLStackItem& newItem)
{
Vector<HTMLStackItem*> candidates;
tryToEnsureNoahsArkConditionQuickly(newItem, candidates);
@@ -172,20 +170,15 @@ void HTMLFormattingElementList::ensureNoahsArkCondition(HTMLStackItem* newItem)
Vector<HTMLStackItem*> remainingCandidates;
remainingCandidates.reserveInitialCapacity(candidates.size());
- const Vector<Attribute>& attributes = newItem->attributes();
- for (size_t i = 0; i < attributes.size(); ++i) {
- const Attribute& attribute = attributes[i];
-
- for (size_t j = 0; j < candidates.size(); ++j) {
- HTMLStackItem* candidate = candidates[j];
-
+ for (auto& attribute : newItem.attributes()) {
+ for (auto& candidate : candidates) {
// These properties should already have been checked by tryToEnsureNoahsArkConditionQuickly.
- ASSERT(newItem->attributes().size() == candidate->attributes().size());
- ASSERT(newItem->localName() == candidate->localName() && newItem->namespaceURI() == candidate->namespaceURI());
+ ASSERT(newItem.attributes().size() == candidate->attributes().size());
+ ASSERT(newItem.localName() == candidate->localName() && newItem.namespaceURI() == candidate->namespaceURI());
- Attribute* candidateAttribute = candidate->getAttributeItem(attribute.name());
+ auto* candidateAttribute = candidate->findAttribute(attribute.name());
if (candidateAttribute && candidateAttribute->value() == attribute.value())
- remainingCandidates.append(candidate);
+ remainingCandidates.uncheckedAppend(candidate);
}
if (remainingCandidates.size() < kNoahsArkCapacity)
@@ -202,7 +195,7 @@ void HTMLFormattingElementList::ensureNoahsArkCondition(HTMLStackItem* newItem)
remove(candidates[i]->element());
}
-#ifndef NDEBUG
+#if ENABLE(TREE_DEBUGGING)
void HTMLFormattingElementList::show()
{
@@ -211,7 +204,7 @@ void HTMLFormattingElementList::show()
if (entry.isMarker())
fprintf(stderr, "marker\n");
else
- entry.element()->showNode();
+ entry.element().showNode();
}
}
diff --git a/Source/WebCore/html/parser/HTMLFormattingElementList.h b/Source/WebCore/html/parser/HTMLFormattingElementList.h
index 35ac17cc2..dfebea343 100644
--- a/Source/WebCore/html/parser/HTMLFormattingElementList.h
+++ b/Source/WebCore/html/parser/HTMLFormattingElementList.h
@@ -23,8 +23,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLFormattingElementList_h
-#define HTMLFormattingElementList_h
+#pragma once
#include "HTMLStackItem.h"
#include <wtf/Forward.h>
@@ -48,32 +47,30 @@ public:
class Entry {
public:
// Inline because they're hot and Vector<T> uses them.
- explicit Entry(PassRefPtr<HTMLStackItem> item)
- : m_item(item)
+ explicit Entry(Ref<HTMLStackItem>&& item)
+ : m_item(WTFMove(item))
{
}
enum MarkerEntryType { MarkerEntry };
Entry(MarkerEntryType)
- : m_item(0)
{
}
- ~Entry() {}
bool isMarker() const { return !m_item; }
- PassRefPtr<HTMLStackItem> stackItem() const { return m_item; }
- Element* element() const
+ HTMLStackItem* stackItem() const { return m_item.get(); }
+ Element& element() const
{
// The fact that !m_item == isMarker() is an implementation detail
// callers should check isMarker() before calling element().
ASSERT(m_item);
return m_item->element();
}
- void replaceElement(PassRefPtr<HTMLStackItem> item) { m_item = item; }
+ void replaceElement(Ref<HTMLStackItem>&& item) { m_item = WTFMove(item); }
// Needed for use with Vector. These are super-hot and must be inline.
- bool operator==(Element* element) const { return !m_item ? !element : m_item->element() == element; }
- bool operator!=(Element* element) const { return !m_item ? !!element : m_item->element() != element; }
+ bool operator==(Element* element) const { return !m_item ? !element : &m_item->element() == element; }
+ bool operator!=(Element* element) const { return !m_item ? !!element : &m_item->element() != element; }
private:
RefPtr<HTMLStackItem> m_item;
@@ -81,20 +78,20 @@ public:
class Bookmark {
public:
- Bookmark(Entry* entry)
+ explicit Bookmark(Entry& entry)
: m_hasBeenMoved(false)
- , m_mark(entry)
+ , m_mark(&entry)
{
}
- void moveToAfter(Entry* before)
+ void moveToAfter(Entry& before)
{
m_hasBeenMoved = true;
- m_mark = before;
+ m_mark = &before;
}
bool hasBeenMoved() const { return m_hasBeenMoved; }
- Entry* mark() const { return m_mark; }
+ Entry& mark() const { ASSERT(m_mark); return *m_mark; }
private:
bool m_hasBeenMoved;
@@ -106,13 +103,13 @@ public:
Element* closestElementInScopeWithName(const AtomicString&);
- Entry* find(Element*);
- bool contains(Element*);
- void append(PassRefPtr<HTMLStackItem>);
- void remove(Element*);
+ Entry* find(Element&);
+ bool contains(Element&);
+ void append(Ref<HTMLStackItem>&&);
+ void remove(Element&);
- Bookmark bookmarkFor(Element*);
- void swapTo(Element* oldElement, PassRefPtr<HTMLStackItem> newItem, const Bookmark&);
+ Bookmark bookmarkFor(Element&);
+ void swapTo(Element& oldElement, Ref<HTMLStackItem>&& newItem, const Bookmark&);
void appendMarker();
// clearToLastMarker also clears the marker (per the HTML5 spec).
@@ -121,21 +118,19 @@ public:
const Entry& at(size_t i) const { return m_entries[i]; }
Entry& at(size_t i) { return m_entries[i]; }
-#ifndef NDEBUG
+#if ENABLE(TREE_DEBUGGING)
void show();
#endif
private:
- Entry* first() { return &at(0); }
+ Entry& first() { return at(0); }
// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#list-of-active-formatting-elements
// These functions enforce the "Noah's Ark" condition, which removes redundant mis-nested elements.
- void tryToEnsureNoahsArkConditionQuickly(HTMLStackItem*, Vector<HTMLStackItem*>& remainingCandiates);
- void ensureNoahsArkCondition(HTMLStackItem*);
+ void tryToEnsureNoahsArkConditionQuickly(HTMLStackItem&, Vector<HTMLStackItem*>& remainingCandidates);
+ void ensureNoahsArkCondition(HTMLStackItem&);
Vector<Entry> m_entries;
};
-}
-
-#endif // HTMLFormattingElementList_h
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLInputStream.h b/Source/WebCore/html/parser/HTMLInputStream.h
index a7b86b3ba..f86e8f8ad 100644
--- a/Source/WebCore/html/parser/HTMLInputStream.h
+++ b/Source/WebCore/html/parser/HTMLInputStream.h
@@ -23,11 +23,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLInputStream_h
-#define HTMLInputStream_h
+#pragma once
-#include "InputStreamPreprocessor.h"
#include "SegmentedString.h"
+#include <wtf/text/TextPosition.h>
namespace WebCore {
@@ -56,14 +55,14 @@ public:
{
}
- void appendToEnd(const SegmentedString& string)
+ void appendToEnd(SegmentedString&& string)
{
- m_last->append(string);
+ m_last->append(WTFMove(string));
}
- void insertAtCurrentInsertionPoint(const SegmentedString& string)
+ void insertAtCurrentInsertionPoint(SegmentedString&& string)
{
- m_first.append(string);
+ m_first.append(WTFMove(string));
}
bool hasInsertionPoint() const
@@ -73,7 +72,7 @@ public:
void markEndOfFile()
{
- m_last->append(SegmentedString(String(&kEndOfFileMarker, 1)));
+ m_last->append(String { &kEndOfFileMarker, 1 });
m_last->close();
}
@@ -92,8 +91,7 @@ public:
void splitInto(SegmentedString& next)
{
- next = m_first;
- m_first = SegmentedString();
+ next = WTFMove(m_first);
if (m_last == &m_first) {
// We used to only have one SegmentedString in the InputStream
// but now we have two. That means m_first is no longer also
@@ -154,6 +152,4 @@ private:
OrdinalNumber m_column;
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLMetaCharsetParser.cpp b/Source/WebCore/html/parser/HTMLMetaCharsetParser.cpp
index 11e14a46e..8a8468915 100644
--- a/Source/WebCore/html/parser/HTMLMetaCharsetParser.cpp
+++ b/Source/WebCore/html/parser/HTMLMetaCharsetParser.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google Inc. All Rights Reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,41 +29,26 @@
#include "HTMLNames.h"
#include "HTMLParserIdioms.h"
-#include "HTMLTokenizer.h"
-#include "TextCodec.h"
#include "TextEncodingRegistry.h"
-using namespace WTF;
-
namespace WebCore {
using namespace HTMLNames;
HTMLMetaCharsetParser::HTMLMetaCharsetParser()
- : m_tokenizer(std::make_unique<HTMLTokenizer>(HTMLParserOptions()))
- , m_assumedCodec(newTextCodec(Latin1Encoding()))
- , m_inHeadSection(true)
- , m_doneChecking(false)
-{
-}
-
-HTMLMetaCharsetParser::~HTMLMetaCharsetParser()
+ : m_codec(newTextCodec(Latin1Encoding()))
{
}
-static const char charsetString[] = "charset";
-static const size_t charsetLength = sizeof("charset") - 1;
-
-String HTMLMetaCharsetParser::extractCharset(const String& value)
+static StringView extractCharset(const String& value)
{
- size_t pos = 0;
unsigned length = value.length();
-
- while (pos < length) {
- pos = value.find(charsetString, pos, false);
+ for (size_t pos = 0; pos < length; ) {
+ pos = value.find("charset", pos, false);
if (pos == notFound)
break;
+ static const size_t charsetLength = sizeof("charset") - 1;
pos += charsetLength;
// Skip whitespace.
@@ -77,12 +63,10 @@ String HTMLMetaCharsetParser::extractCharset(const String& value)
while (pos < length && value[pos] <= ' ')
++pos;
- char quoteMark = 0;
- if (pos < length && (value[pos] == '"' || value[pos] == '\'')) {
- quoteMark = static_cast<char>(value[pos++]);
- ASSERT(!(quoteMark & 0x80));
- }
-
+ UChar quoteMark = 0;
+ if (pos < length && (value[pos] == '"' || value[pos] == '\''))
+ quoteMark = value[pos++];
+
if (pos == length)
break;
@@ -93,19 +77,17 @@ String HTMLMetaCharsetParser::extractCharset(const String& value)
if (quoteMark && (end == length))
break; // Close quote not found.
- return value.substring(pos, end - pos);
+ return StringView(value).substring(pos, end - pos);
}
-
- return "";
+ return StringView();
}
-bool HTMLMetaCharsetParser::processMeta()
+bool HTMLMetaCharsetParser::processMeta(HTMLToken& token)
{
- const HTMLToken::AttributeList& tokenAttributes = m_token.attributes();
AttributeList attributes;
- for (HTMLToken::AttributeList::const_iterator iter = tokenAttributes.begin(); iter != tokenAttributes.end(); ++iter) {
- String attributeName = StringImpl::create8BitIfPossible(iter->name);
- String attributeValue = StringImpl::create8BitIfPossible(iter->value);
+ for (auto& attribute : token.attributes()) {
+ String attributeName = StringImpl::create8BitIfPossible(attribute.name);
+ String attributeValue = StringImpl::create8BitIfPossible(attribute.value);
attributes.append(std::make_pair(attributeName, attributeValue));
}
@@ -116,15 +98,15 @@ bool HTMLMetaCharsetParser::processMeta()
TextEncoding HTMLMetaCharsetParser::encodingFromMetaAttributes(const AttributeList& attributes)
{
bool gotPragma = false;
- Mode mode = None;
- String charset;
+ enum { None, Charset, Pragma } mode = None;
+ StringView charset;
- for (AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter) {
- const AtomicString& attributeName = iter->first;
- const String& attributeValue = iter->second;
+ for (auto& attribute : attributes) {
+ const String& attributeName = attribute.first;
+ const String& attributeValue = attribute.second;
if (attributeName == http_equivAttr) {
- if (equalIgnoringCase(attributeValue, "content-type"))
+ if (equalLettersIgnoringASCIICase(attributeValue, "content-type"))
gotPragma = true;
} else if (charset.isEmpty()) {
if (attributeName == charsetAttr) {
@@ -139,13 +121,11 @@ TextEncoding HTMLMetaCharsetParser::encodingFromMetaAttributes(const AttributeLi
}
if (mode == Charset || (mode == Pragma && gotPragma))
- return TextEncoding(stripLeadingAndTrailingHTMLSpaces(charset));
+ return TextEncoding(stripLeadingAndTrailingHTMLSpaces(charset.toStringWithoutCopying()));
return TextEncoding();
}
-static const int bytesToCheckUnconditionally = 1024; // That many input bytes will be checked for meta charset even if <head> section is over.
-
bool HTMLMetaCharsetParser::checkForMetaCharset(const char* data, size_t length)
{
if (m_doneChecking)
@@ -156,30 +136,32 @@ bool HTMLMetaCharsetParser::checkForMetaCharset(const char* data, size_t length)
// We still don't have an encoding, and are in the head.
// The following tags are allowed in <head>:
// SCRIPT|STYLE|META|LINK|OBJECT|TITLE|BASE
-
+ //
// We stop scanning when a tag that is not permitted in <head>
// is seen, rather when </head> is seen, because that more closely
// matches behavior in other browsers; more details in
// <http://bugs.webkit.org/show_bug.cgi?id=3590>.
-
+ //
// Additionally, we ignore things that looks like tags in <title>, <script>
// and <noscript>; see <http://bugs.webkit.org/show_bug.cgi?id=4560>,
// <http://bugs.webkit.org/show_bug.cgi?id=12165> and
// <http://bugs.webkit.org/show_bug.cgi?id=12389>.
-
+ //
// Since many sites have charset declarations after <body> or other tags
// that are disallowed in <head>, we don't bail out until we've checked at
// least bytesToCheckUnconditionally bytes of input.
- m_input.append(SegmentedString(m_assumedCodec->decode(data, length)));
+ constexpr int bytesToCheckUnconditionally = 1024;
+
+ m_input.append(m_codec->decode(data, length));
- while (m_tokenizer->nextToken(m_input, m_token)) {
- bool end = m_token.type() == HTMLToken::EndTag;
- if (end || m_token.type() == HTMLToken::StartTag) {
- AtomicString tagName(m_token.name());
- if (!end) {
- m_tokenizer->updateStateFor(tagName);
- if (tagName == metaTag && processMeta()) {
+ while (auto token = m_tokenizer.nextToken(m_input)) {
+ bool isEnd = token->type() == HTMLToken::EndTag;
+ if (isEnd || token->type() == HTMLToken::StartTag) {
+ AtomicString tagName(token->name());
+ if (!isEnd) {
+ m_tokenizer.updateStateFor(tagName);
+ if (tagName == metaTag && processMeta(*token)) {
m_doneChecking = true;
return true;
}
@@ -189,7 +171,8 @@ bool HTMLMetaCharsetParser::checkForMetaCharset(const char* data, size_t length)
&& tagName != styleTag && tagName != linkTag
&& tagName != metaTag && tagName != objectTag
&& tagName != titleTag && tagName != baseTag
- && (end || tagName != htmlTag) && (end || tagName != headTag)) {
+ && (isEnd || tagName != htmlTag)
+ && (isEnd || tagName != headTag)) {
m_inHeadSection = false;
}
}
@@ -198,8 +181,6 @@ bool HTMLMetaCharsetParser::checkForMetaCharset(const char* data, size_t length)
m_doneChecking = true;
return true;
}
-
- m_token.clear();
}
return false;
diff --git a/Source/WebCore/html/parser/HTMLMetaCharsetParser.h b/Source/WebCore/html/parser/HTMLMetaCharsetParser.h
index 618ce7ff6..8d7b89fa5 100644
--- a/Source/WebCore/html/parser/HTMLMetaCharsetParser.h
+++ b/Source/WebCore/html/parser/HTMLMetaCharsetParser.h
@@ -23,54 +23,39 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLMetaCharsetParser_h
-#define HTMLMetaCharsetParser_h
+#pragma once
-#include "HTMLToken.h"
+#include "HTMLTokenizer.h"
#include "SegmentedString.h"
#include "TextEncoding.h"
-#include <wtf/Noncopyable.h>
namespace WebCore {
-class HTMLTokenizer;
class TextCodec;
class HTMLMetaCharsetParser {
WTF_MAKE_NONCOPYABLE(HTMLMetaCharsetParser); WTF_MAKE_FAST_ALLOCATED;
public:
HTMLMetaCharsetParser();
- ~HTMLMetaCharsetParser();
// Returns true if done checking, regardless whether an encoding is found.
bool checkForMetaCharset(const char*, size_t);
const TextEncoding& encoding() { return m_encoding; }
- typedef Vector<std::pair<String, String>> AttributeList;
// The returned encoding might not be valid.
- static TextEncoding encodingFromMetaAttributes(const AttributeList&
-);
+ typedef Vector<std::pair<String, String>> AttributeList;
+ static TextEncoding encodingFromMetaAttributes(const AttributeList&);
private:
- bool processMeta();
- static String extractCharset(const String&);
+ bool processMeta(HTMLToken&);
- enum Mode {
- None,
- Charset,
- Pragma,
- };
-
- std::unique_ptr<HTMLTokenizer> m_tokenizer;
- OwnPtr<TextCodec> m_assumedCodec;
+ HTMLTokenizer m_tokenizer;
+ const std::unique_ptr<TextCodec> m_codec;
SegmentedString m_input;
- HTMLToken m_token;
- bool m_inHeadSection;
-
- bool m_doneChecking;
+ bool m_inHeadSection { true };
+ bool m_doneChecking { false };
TextEncoding m_encoding;
};
-}
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLParserIdioms.cpp b/Source/WebCore/html/parser/HTMLParserIdioms.cpp
index 43dd13ce4..e20276d6d 100644
--- a/Source/WebCore/html/parser/HTMLParserIdioms.cpp
+++ b/Source/WebCore/html/parser/HTMLParserIdioms.cpp
@@ -26,10 +26,12 @@
#include "HTMLParserIdioms.h"
#include "Decimal.h"
+#include "QualifiedName.h"
#include "URL.h"
#include <limits>
#include <wtf/MathExtras.h>
-#include <wtf/text/AtomicString.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/dtoa.h>
#include <wtf/text/StringBuilder.h>
namespace WebCore {
@@ -71,7 +73,7 @@ String stripLeadingAndTrailingHTMLSpaces(const String& string)
if (string.is8Bit())
return stripLeadingAndTrailingHTMLSpaces(string, string.characters8(), length);
- return stripLeadingAndTrailingHTMLSpaces(string, string.deprecatedCharacters(), length);
+ return stripLeadingAndTrailingHTMLSpaces(string, string.characters16(), length);
}
String serializeForNumberType(const Decimal& number)
@@ -152,276 +154,314 @@ double parseToDoubleForNumberType(const String& string)
}
template <typename CharacterType>
-static bool parseHTMLIntegerInternal(const CharacterType* position, const CharacterType* end, int& value)
+static std::optional<int> parseHTMLIntegerInternal(const CharacterType* position, const CharacterType* end)
{
- // Step 3
- int sign = 1;
-
- // Step 4
- while (position < end) {
- if (!isHTMLSpace(*position))
- break;
+ while (position < end && isHTMLSpace(*position))
++position;
- }
- // Step 5
if (position == end)
- return false;
- ASSERT_WITH_SECURITY_IMPLICATION(position < end);
+ return std::nullopt;
- // Step 6
+ bool isNegative = false;
if (*position == '-') {
- sign = -1;
+ isNegative = true;
++position;
} else if (*position == '+')
++position;
- if (position == end)
- return false;
- ASSERT_WITH_SECURITY_IMPLICATION(position < end);
- // Step 7
- if (!isASCIIDigit(*position))
- return false;
+ if (position == end || !isASCIIDigit(*position))
+ return std::nullopt;
- // Step 8
- StringBuilder digits;
- while (position < end) {
- if (!isASCIIDigit(*position))
- break;
- digits.append(*position++);
- }
+ constexpr int intMax = std::numeric_limits<int>::max();
+ constexpr int base = 10;
+ constexpr int maxMultiplier = intMax / base;
- // Step 9
- bool ok;
- if (digits.is8Bit())
- value = sign * charactersToIntStrict(digits.characters8(), digits.length(), &ok);
- else
- value = sign * charactersToIntStrict(digits.characters16(), digits.length(), &ok);
- return ok;
+ unsigned result = 0;
+ do {
+ int digitValue = *position - '0';
+
+ if (result > maxMultiplier || (result == maxMultiplier && digitValue > (intMax % base) + isNegative))
+ return std::nullopt;
+
+ result = base * result + digitValue;
+ ++position;
+ } while (position < end && isASCIIDigit(*position));
+
+ return isNegative ? -result : result;
}
-// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers
-bool parseHTMLInteger(const String& input, int& value)
+// https://html.spec.whatwg.org/multipage/infrastructure.html#rules-for-parsing-integers
+std::optional<int> parseHTMLInteger(StringView input)
{
- // Step 1
- // Step 2
unsigned length = input.length();
- if (!length || input.is8Bit()) {
- const LChar* start = input.characters8();
- return parseHTMLIntegerInternal(start, start + length, value);
+ if (!length)
+ return std::nullopt;
+
+ if (LIKELY(input.is8Bit())) {
+ auto* start = input.characters8();
+ return parseHTMLIntegerInternal(start, start + length);
}
- const UChar* start = input.characters16();
- return parseHTMLIntegerInternal(start, start + length, value);
+ auto* start = input.characters16();
+ return parseHTMLIntegerInternal(start, start + length);
+}
+
+// https://html.spec.whatwg.org/multipage/infrastructure.html#rules-for-parsing-non-negative-integers
+std::optional<unsigned> parseHTMLNonNegativeInteger(StringView input)
+{
+ std::optional<int> signedValue = parseHTMLInteger(input);
+ if (!signedValue || signedValue.value() < 0)
+ return std::nullopt;
+
+ return static_cast<unsigned>(signedValue.value());
}
template <typename CharacterType>
-static bool parseHTMLNonNegativeIntegerInternal(const CharacterType* position, const CharacterType* end, unsigned& value)
+static std::optional<int> parseValidHTMLNonNegativeIntegerInternal(const CharacterType* position, const CharacterType* end)
{
- // Step 3
- while (position < end) {
- if (!isHTMLSpace(*position))
- break;
- ++position;
+ // A string is a valid non-negative integer if it consists of one or more ASCII digits.
+ for (auto* c = position; c < end; ++c) {
+ if (!isASCIIDigit(*c))
+ return std::nullopt;
}
- // Step 4
- if (position == end)
- return false;
- ASSERT_WITH_SECURITY_IMPLICATION(position < end);
-
- // Step 5
- if (*position == '+')
- ++position;
+ std::optional<int> signedValue = parseHTMLIntegerInternal(position, end);
+ if (!signedValue || signedValue.value() < 0)
+ return std::nullopt;
- // Step 6
- if (position == end)
- return false;
- ASSERT_WITH_SECURITY_IMPLICATION(position < end);
+ return signedValue;
+}
- // Step 7
- if (!isASCIIDigit(*position))
- return false;
+// https://html.spec.whatwg.org/#valid-non-negative-integer
+std::optional<int> parseValidHTMLNonNegativeInteger(StringView input)
+{
+ if (input.isEmpty())
+ return std::nullopt;
- // Step 8
- StringBuilder digits;
- while (position < end) {
- if (!isASCIIDigit(*position))
- break;
- digits.append(*position++);
+ if (LIKELY(input.is8Bit())) {
+ auto* start = input.characters8();
+ return parseValidHTMLNonNegativeIntegerInternal(start, start + input.length());
}
- // Step 9
- bool ok;
- if (digits.is8Bit())
- value = charactersToUIntStrict(digits.characters8(), digits.length(), &ok);
- else
- value = charactersToUIntStrict(digits.characters16(), digits.length(), &ok);
- return ok;
+ auto* start = input.characters16();
+ return parseValidHTMLNonNegativeIntegerInternal(start, start + input.length());
}
+template <typename CharacterType>
+static std::optional<double> parseValidHTMLFloatingPointNumberInternal(const CharacterType* position, size_t length)
+{
+ ASSERT(length > 0);
+
+ // parseDouble() allows the string to start with a '+' or to end with a '.' but those
+ // are not valid floating point numbers as per HTML.
+ if (*position == '+' || *(position + length - 1) == '.')
+ return std::nullopt;
-// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-non-negative-integers
-bool parseHTMLNonNegativeInteger(const String& input, unsigned& value)
+ size_t parsedLength = 0;
+ double number = parseDouble(position, length, parsedLength);
+ return parsedLength == length && std::isfinite(number) ? number : std::optional<double>();
+}
+
+// https://html.spec.whatwg.org/#valid-floating-point-number
+std::optional<double> parseValidHTMLFloatingPointNumber(StringView input)
{
- // Step 1
- // Step 2
- unsigned length = input.length();
- if (length && input.is8Bit()) {
- const LChar* start = input.characters8();
- return parseHTMLNonNegativeIntegerInternal(start, start + length, value);
+ if (input.isEmpty())
+ return std::nullopt;
+
+ if (LIKELY(input.is8Bit())) {
+ auto* start = input.characters8();
+ return parseValidHTMLFloatingPointNumberInternal(start, input.length());
}
-
- const UChar* start = input.deprecatedCharacters();
- return parseHTMLNonNegativeIntegerInternal(start, start + length, value);
+
+ auto* start = input.characters16();
+ return parseValidHTMLFloatingPointNumberInternal(start, input.length());
}
-static bool threadSafeEqual(const StringImpl* a, const StringImpl* b)
+static inline bool isHTMLSpaceOrDelimiter(UChar character)
{
- if (a == b)
- return true;
- if (a->hash() != b->hash())
- return false;
- return equalNonNull(a, b);
+ return isHTMLSpace(character) || character == ',' || character == ';';
}
-bool threadSafeMatch(const QualifiedName& a, const QualifiedName& b)
+static inline bool isNumberStart(UChar character)
{
- return threadSafeEqual(a.localName().impl(), b.localName().impl());
+ return isASCIIDigit(character) || character == '.' || character == '-';
}
-struct ImageWithScale {
- unsigned imageURLStart;
- unsigned imageURLLength;
- float scaleFactor;
+// https://html.spec.whatwg.org/multipage/infrastructure.html#rules-for-parsing-floating-point-number-values
+template <typename CharacterType>
+static Vector<double> parseHTMLListOfOfFloatingPointNumberValuesInternal(const CharacterType* position, const CharacterType* end)
+{
+ Vector<double> numbers;
+
+ // This skips past any leading delimiters.
+ while (position < end && isHTMLSpaceOrDelimiter(*position))
+ ++position;
+
+ while (position < end) {
+ // This skips past leading garbage.
+ while (position < end && !(isHTMLSpaceOrDelimiter(*position) || isNumberStart(*position)))
+ ++position;
+
+ const CharacterType* numberStart = position;
+ while (position < end && !isHTMLSpaceOrDelimiter(*position))
+ ++position;
+
+ size_t parsedLength = 0;
+ double number = parseDouble(numberStart, position - numberStart, parsedLength);
+ numbers.append(parsedLength > 0 && std::isfinite(number) ? number : 0);
- ImageWithScale()
- : imageURLStart(0)
- , imageURLLength(0)
- , scaleFactor(1)
- {
+ // This skips past the delimiter.
+ while (position < end && isHTMLSpaceOrDelimiter(*position))
+ ++position;
}
- bool hasImageURL() const
- {
- return imageURLLength;
+ return numbers;
+}
+
+Vector<double> parseHTMLListOfOfFloatingPointNumberValues(StringView input)
+{
+ if (LIKELY(input.is8Bit())) {
+ auto* start = input.characters8();
+ return parseHTMLListOfOfFloatingPointNumberValuesInternal(start, start + input.length());
}
-};
-typedef Vector<ImageWithScale> ImageCandidates;
-static inline bool compareByScaleFactor(const ImageWithScale& first, const ImageWithScale& second)
+ auto* start = input.characters16();
+ return parseHTMLListOfOfFloatingPointNumberValuesInternal(start, start + input.length());
+}
+
+static bool threadSafeEqual(const StringImpl& a, const StringImpl& b)
{
- return first.scaleFactor < second.scaleFactor;
+ if (&a == &b)
+ return true;
+ if (a.hash() != b.hash())
+ return false;
+ return equal(a, b);
}
-static inline bool isHTMLSpaceOrComma(UChar character)
+bool threadSafeMatch(const QualifiedName& a, const QualifiedName& b)
{
- return isHTMLSpace(character) || character == ',';
+ return threadSafeEqual(*a.localName().impl(), *b.localName().impl());
}
-// See the specifications for more details about the algorithm to follow.
-// http://www.w3.org/TR/2013/WD-html-srcset-20130228/#processing-the-image-candidates.
-static void parseImagesWithScaleFromSrcsetAttribute(const String& srcsetAttribute, ImageCandidates& imageCandidates)
+String parseCORSSettingsAttribute(const AtomicString& value)
{
- ASSERT(imageCandidates.isEmpty());
+ if (value.isNull())
+ return String();
+ if (equalIgnoringASCIICase(value, "use-credentials"))
+ return ASCIILiteral("use-credentials");
+ return ASCIILiteral("anonymous");
+}
- size_t imageCandidateStart = 0;
- unsigned srcsetAttributeLength = srcsetAttribute.length();
+// https://html.spec.whatwg.org/multipage/semantics.html#attr-meta-http-equiv-refresh
+template <typename CharacterType>
+static bool parseHTTPRefreshInternal(const CharacterType* position, const CharacterType* end, double& parsedDelay, String& parsedURL)
+{
+ while (position < end && isHTMLSpace(*position))
+ ++position;
- while (imageCandidateStart < srcsetAttributeLength) {
- float imageScaleFactor = 1;
- size_t separator;
+ const CharacterType* numberStart = position;
+ while (position < end && isASCIIDigit(*position))
+ ++position;
- // 4. Splitting loop: Skip whitespace.
- size_t imageURLStart = srcsetAttribute.find(isNotHTMLSpace, imageCandidateStart);
- if (imageURLStart == notFound)
- break;
- // If The current candidate is either totally empty or only contains space, skipping.
- if (srcsetAttribute[imageURLStart] == ',') {
- imageCandidateStart = imageURLStart + 1;
- continue;
+ std::optional<unsigned> number = parseHTMLNonNegativeInteger(StringView(numberStart, position - numberStart));
+ if (!number)
+ return false;
+
+ while (position < end && (isASCIIDigit(*position) || *position == '.'))
+ ++position;
+
+ if (position == end) {
+ parsedDelay = number.value();
+ return true;
+ }
+
+ if (*position != ';' && *position != ',' && !isHTMLSpace(*position))
+ return false;
+
+ parsedDelay = number.value();
+
+ while (position < end && isHTMLSpace(*position))
+ ++position;
+
+ if (position < end && (*position == ';' || *position == ','))
+ ++position;
+
+ while (position < end && isHTMLSpace(*position))
+ ++position;
+
+ if (position == end)
+ return true;
+
+ if (*position == 'U' || *position == 'u') {
+ StringView url(position, end - position);
+
+ ++position;
+
+ if (position < end && (*position == 'R' || *position == 'r'))
+ ++position;
+ else {
+ parsedURL = url.toString();
+ return true;
}
- // 5. Collect a sequence of characters that are not space characters, and let that be url.
- size_t imageURLEnd = srcsetAttribute.find(isHTMLSpace, imageURLStart + 1);
- if (imageURLEnd == notFound) {
- imageURLEnd = srcsetAttributeLength;
- separator = srcsetAttributeLength;
- } else if (srcsetAttribute[imageURLEnd - 1] == ',') {
- --imageURLEnd;
- separator = imageURLEnd;
- } else {
- // 7. Collect a sequence of characters that are not "," (U+002C) characters, and let that be descriptors.
- size_t imageScaleStart = srcsetAttribute.find(isNotHTMLSpace, imageURLEnd + 1);
- if (imageScaleStart == notFound)
- separator = srcsetAttributeLength;
- else if (srcsetAttribute[imageScaleStart] == ',')
- separator = imageScaleStart;
- else {
- // This part differs from the spec as the current implementation only supports pixel density descriptors for now.
- size_t imageScaleEnd = srcsetAttribute.find(isHTMLSpaceOrComma, imageScaleStart + 1);
- imageScaleEnd = (imageScaleEnd == notFound) ? srcsetAttributeLength : imageScaleEnd;
- size_t commaPosition = imageScaleEnd;
- // Make sure there are no other descriptors.
- while ((commaPosition < srcsetAttributeLength - 1) && isHTMLSpace(srcsetAttribute[commaPosition]))
- ++commaPosition;
- // If the first not html space character after the scale modifier is not a comma,
- // the current candidate is an invalid input.
- if ((commaPosition < srcsetAttributeLength - 1) && srcsetAttribute[commaPosition] != ',') {
- // Find the nearest comma and skip the input.
- commaPosition = srcsetAttribute.find(',', commaPosition + 1);
- if (commaPosition == notFound)
- break;
- imageCandidateStart = commaPosition + 1;
- continue;
- }
- separator = commaPosition;
- if (srcsetAttribute[imageScaleEnd - 1] != 'x') {
- imageCandidateStart = separator + 1;
- continue;
- }
- bool validScaleFactor = false;
- size_t scaleFactorLengthWithoutUnit = imageScaleEnd - imageScaleStart - 1;
- imageScaleFactor = charactersToFloat(srcsetAttribute.deprecatedCharacters() + imageScaleStart, scaleFactorLengthWithoutUnit, &validScaleFactor);
-
- if (!validScaleFactor) {
- imageCandidateStart = separator + 1;
- continue;
- }
- }
+
+ if (position < end && (*position == 'L' || *position == 'l'))
+ ++position;
+ else {
+ parsedURL = url.toString();
+ return true;
}
- ImageWithScale image;
- image.imageURLStart = imageURLStart;
- image.imageURLLength = imageURLEnd - imageURLStart;
- image.scaleFactor = imageScaleFactor;
-
- imageCandidates.append(image);
- // 11. Return to the step labeled splitting loop.
- imageCandidateStart = separator + 1;
- }
-}
-String bestFitSourceForImageAttributes(float deviceScaleFactor, const String& srcAttribute, const String& srcsetAttribute)
-{
- ImageCandidates imageCandidates;
+ while (position < end && isHTMLSpace(*position))
+ ++position;
- parseImagesWithScaleFromSrcsetAttribute(srcsetAttribute, imageCandidates);
+ if (position < end && *position == '=')
+ ++position;
+ else {
+ parsedURL = url.toString();
+ return true;
+ }
- if (!srcAttribute.isEmpty()) {
- ImageWithScale srcPlaceholderImage;
- imageCandidates.append(srcPlaceholderImage);
+ while (position < end && isHTMLSpace(*position))
+ ++position;
}
- if (imageCandidates.isEmpty())
- return String();
+ CharacterType quote;
+ if (position < end && (*position == '\'' || *position == '"')) {
+ quote = *position;
+ ++position;
+ } else
+ quote = '\0';
- std::stable_sort(imageCandidates.begin(), imageCandidates.end(), compareByScaleFactor);
+ StringView url(position, end - position);
- for (size_t i = 0; i < imageCandidates.size() - 1; ++i) {
- if (imageCandidates[i].scaleFactor >= deviceScaleFactor)
- return imageCandidates[i].hasImageURL() ? srcsetAttribute.substringSharingImpl(imageCandidates[i].imageURLStart, imageCandidates[i].imageURLLength) : srcAttribute;
+ if (quote != '\0') {
+ size_t index = url.find(quote);
+ if (index != notFound)
+ url = url.substring(0, index);
}
- const ImageWithScale& lastCandidate = imageCandidates.last();
- return lastCandidate.hasImageURL() ? srcsetAttribute.substringSharingImpl(lastCandidate.imageURLStart, lastCandidate.imageURLLength) : srcAttribute;
+
+ parsedURL = url.toString();
+ return true;
+}
+
+bool parseMetaHTTPEquivRefresh(const StringView& input, double& delay, String& url)
+{
+ if (LIKELY(input.is8Bit())) {
+ auto* start = input.characters8();
+ return parseHTTPRefreshInternal(start, start + input.length(), delay, url);
+ }
+
+ auto* start = input.characters16();
+ return parseHTTPRefreshInternal(start, start + input.length(), delay, url);
+}
+
+// https://html.spec.whatwg.org/#rules-for-parsing-a-hash-name-reference
+AtomicString parseHTMLHashNameReference(StringView usemap)
+{
+ size_t numberSignIndex = usemap.find('#');
+ if (numberSignIndex == notFound)
+ return nullAtom;
+ return usemap.substring(numberSignIndex + 1).toAtomicString();
}
}
diff --git a/Source/WebCore/html/parser/HTMLParserIdioms.h b/Source/WebCore/html/parser/HTMLParserIdioms.h
index 7c5914248..29a6c6ed3 100644
--- a/Source/WebCore/html/parser/HTMLParserIdioms.h
+++ b/Source/WebCore/html/parser/HTMLParserIdioms.h
@@ -22,30 +22,32 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLParserIdioms_h
-#define HTMLParserIdioms_h
+#pragma once
-#include "QualifiedName.h"
+#include <unicode/uchar.h>
#include <wtf/Forward.h>
-#include <wtf/text/WTFString.h>
+#include <wtf/Optional.h>
+#include <wtf/Vector.h>
+#include <wtf/text/StringView.h>
namespace WebCore {
class Decimal;
+class QualifiedName;
// Space characters as defined by the HTML specification.
-bool isHTMLSpace(UChar);
+template<typename CharacterType> bool isHTMLSpace(CharacterType);
+template<typename CharacterType> bool isComma(CharacterType);
+template<typename CharacterType> bool isHTMLSpaceOrComma(CharacterType);
bool isHTMLLineBreak(UChar);
bool isNotHTMLSpace(UChar);
-bool isHTMLSpaceButNotLineBreak(UChar character);
+bool isHTMLSpaceButNotLineBreak(UChar);
+
+// 2147483647 is 2^31 - 1.
+static const unsigned maxHTMLNonNegativeInteger = 2147483647;
// Strip leading and trailing whitespace as defined by the HTML specification.
-String stripLeadingAndTrailingHTMLSpaces(const String&);
-template<size_t inlineCapacity>
-String stripLeadingAndTrailingHTMLSpaces(const Vector<UChar, inlineCapacity>& vector)
-{
- return stripLeadingAndTrailingHTMLSpaces(StringImpl::create8BitIfPossible(vector));
-}
+WEBCORE_EXPORT String stripLeadingAndTrailingHTMLSpaces(const String&);
// An implementation of the HTML specification's algorithm to convert a number to a string for number and range types.
String serializeForNumberType(const Decimal&);
@@ -60,14 +62,33 @@ double parseToDoubleForNumberType(const String&);
double parseToDoubleForNumberType(const String&, double fallbackValue);
// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers
-bool parseHTMLInteger(const String&, int&);
+WEBCORE_EXPORT std::optional<int> parseHTMLInteger(StringView);
// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-non-negative-integers
-bool parseHTMLNonNegativeInteger(const String&, unsigned int&);
+WEBCORE_EXPORT std::optional<unsigned> parseHTMLNonNegativeInteger(StringView);
+
+// https://html.spec.whatwg.org/#valid-non-negative-integer
+std::optional<int> parseValidHTMLNonNegativeInteger(StringView);
+
+// https://html.spec.whatwg.org/#valid-floating-point-number
+std::optional<double> parseValidHTMLFloatingPointNumber(StringView);
+
+// https://html.spec.whatwg.org/multipage/infrastructure.html#rules-for-parsing-floating-point-number-values
+Vector<double> parseHTMLListOfOfFloatingPointNumberValues(StringView);
+
+// https://html.spec.whatwg.org/multipage/semantics.html#attr-meta-http-equiv-refresh
+bool parseMetaHTTPEquivRefresh(const StringView&, double& delay, String& url);
+
+// https://html.spec.whatwg.org/multipage/infrastructure.html#cors-settings-attribute
+String parseCORSSettingsAttribute(const AtomicString&);
+
+bool threadSafeMatch(const QualifiedName&, const QualifiedName&);
+
+AtomicString parseHTMLHashNameReference(StringView);
// Inline implementations of some of the functions declared above.
-inline bool isHTMLSpace(UChar character)
+template<typename CharacterType> inline bool isHTMLSpace(CharacterType character)
{
// Histogram from Apple's page load test combined with some ad hoc browsing some other test suites.
//
@@ -87,6 +108,16 @@ inline bool isHTMLLineBreak(UChar character)
return character <= '\r' && (character == '\n' || character == '\r');
}
+template<typename CharacterType> inline bool isComma(CharacterType character)
+{
+ return character == ',';
+}
+
+template<typename CharacterType> inline bool isHTMLSpaceOrComma(CharacterType character)
+{
+ return isComma(character) || isHTMLSpace(character);
+}
+
inline bool isNotHTMLSpace(UChar character)
{
return !isHTMLSpace(character);
@@ -97,10 +128,36 @@ inline bool isHTMLSpaceButNotLineBreak(UChar character)
return isHTMLSpace(character) && !isHTMLLineBreak(character);
}
-bool threadSafeMatch(const QualifiedName&, const QualifiedName&);
+// https://html.spec.whatwg.org/multipage/infrastructure.html#limited-to-only-non-negative-numbers-greater-than-zero
+inline unsigned limitToOnlyHTMLNonNegativeNumbersGreaterThanZero(unsigned value, unsigned defaultValue = 1)
+{
+ return (value > 0 && value <= maxHTMLNonNegativeInteger) ? value : defaultValue;
+}
-String bestFitSourceForImageAttributes(float deviceScaleFactor, const String& srcAttribute, const String& sourceSetAttribute);
+inline unsigned limitToOnlyHTMLNonNegativeNumbersGreaterThanZero(StringView stringValue, unsigned defaultValue = 1)
+{
+ ASSERT(defaultValue > 0);
+ ASSERT(defaultValue <= maxHTMLNonNegativeInteger);
+ auto optionalValue = parseHTMLNonNegativeInteger(stringValue);
+ unsigned value = optionalValue && optionalValue.value() ? optionalValue.value() : defaultValue;
+ ASSERT(value > 0);
+ ASSERT(value <= maxHTMLNonNegativeInteger);
+ return value;
+}
+
+// https://html.spec.whatwg.org/#reflecting-content-attributes-in-idl-attributes:idl-unsigned-long
+inline unsigned limitToOnlyHTMLNonNegative(unsigned value, unsigned defaultValue = 0)
+{
+ ASSERT(defaultValue <= maxHTMLNonNegativeInteger);
+ return value <= maxHTMLNonNegativeInteger ? value : defaultValue;
+}
+inline unsigned limitToOnlyHTMLNonNegative(StringView stringValue, unsigned defaultValue = 0)
+{
+ ASSERT(defaultValue <= maxHTMLNonNegativeInteger);
+ unsigned value = parseHTMLNonNegativeInteger(stringValue).value_or(defaultValue);
+ ASSERT(value <= maxHTMLNonNegativeInteger);
+ return value;
}
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLParserOptions.cpp b/Source/WebCore/html/parser/HTMLParserOptions.cpp
index 000d4b02b..0d2d9fb3b 100644
--- a/Source/WebCore/html/parser/HTMLParserOptions.cpp
+++ b/Source/WebCore/html/parser/HTMLParserOptions.cpp
@@ -47,11 +47,10 @@ HTMLParserOptions::HTMLParserOptions(Document& document)
{
Frame* frame = document.frame();
scriptEnabled = frame && frame->script().canExecuteScripts(NotAboutToExecuteScript);
- pluginsEnabled = frame && frame->loader().subframeLoader().allowPlugins(NotAboutToInstantiatePlugin);
+ pluginsEnabled = frame && frame->loader().subframeLoader().allowPlugins();
- Settings* settings = document.settings();
- usePreHTML5ParserQuirks = settings && settings->usePreHTML5ParserQuirks();
- maximumDOMTreeDepth = settings ? settings->maximumHTMLParserDOMTreeDepth() : Settings::defaultMaximumHTMLParserDOMTreeDepth;
+ usePreHTML5ParserQuirks = document.settings().usePreHTML5ParserQuirks();
+ maximumDOMTreeDepth = document.settings().maximumHTMLParserDOMTreeDepth();
}
}
diff --git a/Source/WebCore/html/parser/HTMLParserOptions.h b/Source/WebCore/html/parser/HTMLParserOptions.h
index 1d79c2beb..f468d8797 100644
--- a/Source/WebCore/html/parser/HTMLParserOptions.h
+++ b/Source/WebCore/html/parser/HTMLParserOptions.h
@@ -23,8 +23,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLParserOptions_h
-#define HTMLParserOptions_h
+#pragma once
namespace WebCore {
@@ -41,6 +40,4 @@ public:
unsigned maximumDOMTreeDepth;
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLParserScheduler.cpp b/Source/WebCore/html/parser/HTMLParserScheduler.cpp
index 974fcbec9..28337d86d 100644
--- a/Source/WebCore/html/parser/HTMLParserScheduler.cpp
+++ b/Source/WebCore/html/parser/HTMLParserScheduler.cpp
@@ -32,11 +32,6 @@
#include "HTMLDocumentParser.h"
#include "Page.h"
-// defaultParserChunkSize is used to define how many tokens the parser will
-// process before checking against parserTimeLimit and possibly yielding.
-// This is a performance optimization to prevent checking after every token.
-static const int defaultParserChunkSize = 4096;
-
// defaultParserTimeLimit is the seconds the parser will run in one write() call
// before yielding. Inline <script> execution can cause it to exceed the limit.
// FIXME: We would like this value to be 0.2.
@@ -52,16 +47,6 @@ static double parserTimeLimit(Page* page)
return defaultParserTimeLimit;
}
-static int parserChunkSize(Page* page)
-{
- // FIXME: We may need to divide the value from customHTMLTokenizerChunkSize
- // by some constant to translate from the "character" based behavior of the
- // old LegacyHTMLDocumentParser to the token-based behavior of this parser.
- if (page && page->hasCustomHTMLTokenizerChunkSize())
- return page->customHTMLTokenizerChunkSize();
- return defaultParserChunkSize;
-}
-
ActiveParserSession::ActiveParserSession(Document* document)
: m_document(document)
{
@@ -85,7 +70,6 @@ PumpSession::PumpSession(unsigned& nestingLevel, Document* document)
// At that time we'll initialize startTime.
, processedTokens(INT_MAX)
, startTime(0)
- , needsYield(false)
, didSeeScript(false)
{
}
@@ -97,8 +81,7 @@ PumpSession::~PumpSession()
HTMLParserScheduler::HTMLParserScheduler(HTMLDocumentParser& parser)
: m_parser(parser)
, m_parserTimeLimit(parserTimeLimit(m_parser.document()->page()))
- , m_parserChunkSize(parserChunkSize(m_parser.document()->page()))
- , m_continueNextChunkTimer(this, &HTMLParserScheduler::continueNextChunkTimerFired)
+ , m_continueNextChunkTimer(*this, &HTMLParserScheduler::continueNextChunkTimerFired)
, m_isSuspendedWithActiveTimer(false)
#if !ASSERT_DISABLED
, m_suspended(false)
@@ -111,10 +94,9 @@ HTMLParserScheduler::~HTMLParserScheduler()
m_continueNextChunkTimer.stop();
}
-void HTMLParserScheduler::continueNextChunkTimerFired(Timer<HTMLParserScheduler>& timer)
+void HTMLParserScheduler::continueNextChunkTimerFired()
{
ASSERT(!m_suspended);
- ASSERT_UNUSED(timer, &timer == &m_continueNextChunkTimer);
// FIXME: The timer class should handle timer priorities instead of this code.
// If a layout is scheduled, wait again to let the layout timer run first.
@@ -125,15 +107,14 @@ void HTMLParserScheduler::continueNextChunkTimerFired(Timer<HTMLParserScheduler>
m_parser.resumeParsingAfterYield();
}
-void HTMLParserScheduler::checkForYieldBeforeScript(PumpSession& session)
+bool HTMLParserScheduler::shouldYieldBeforeExecutingScript(PumpSession& session)
{
// If we've never painted before and a layout is pending, yield prior to running
// scripts to give the page a chance to paint earlier.
Document* document = m_parser.document();
bool needsFirstPaint = document->view() && !document->view()->hasEverPainted();
- if (needsFirstPaint && document->isLayoutTimerActive())
- session.needsYield = true;
session.didSeeScript = true;
+ return needsFirstPaint && document->isLayoutTimerActive();
}
void HTMLParserScheduler::scheduleForResume()
diff --git a/Source/WebCore/html/parser/HTMLParserScheduler.h b/Source/WebCore/html/parser/HTMLParserScheduler.h
index 862bb62a4..a79e06450 100644
--- a/Source/WebCore/html/parser/HTMLParserScheduler.h
+++ b/Source/WebCore/html/parser/HTMLParserScheduler.h
@@ -23,13 +23,11 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLParserScheduler_h
-#define HTMLParserScheduler_h
+#pragma once
#include "NestingLevelIncrementer.h"
#include "Timer.h"
#include <wtf/CurrentTime.h>
-#include <wtf/PassOwnPtr.h>
#include <wtf/RefPtr.h>
#if PLATFORM(IOS)
@@ -55,9 +53,8 @@ public:
PumpSession(unsigned& nestingLevel, Document*);
~PumpSession();
- int processedTokens;
+ unsigned processedTokens;
double startTime;
- bool needsYield;
bool didSeeScript;
};
@@ -67,29 +64,19 @@ public:
explicit HTMLParserScheduler(HTMLDocumentParser&);
~HTMLParserScheduler();
- // Inline as this is called after every token in the parser.
- void checkForYieldBeforeToken(PumpSession& session)
+ bool shouldYieldBeforeToken(PumpSession& session)
{
#if PLATFORM(IOS)
if (WebThreadShouldYield())
- session.needsYield = true;
+ return true;
#endif
- if (session.processedTokens > m_parserChunkSize || session.didSeeScript) {
- // monotonicallyIncreasingTime() can be expensive. By delaying, we avoided calling
- // monotonicallyIncreasingTime() when constructing non-yielding PumpSessions.
- if (!session.startTime)
- session.startTime = monotonicallyIncreasingTime();
-
- session.processedTokens = 0;
- session.didSeeScript = false;
-
- double elapsedTime = monotonicallyIncreasingTime() - session.startTime;
- if (elapsedTime > m_parserTimeLimit)
- session.needsYield = true;
- }
+ if (UNLIKELY(session.processedTokens > numberOfTokensBeforeCheckingForYield || session.didSeeScript))
+ return checkForYield(session);
+
++session.processedTokens;
+ return false;
}
- void checkForYieldBeforeScript(PumpSession&);
+ bool shouldYieldBeforeExecutingScript(PumpSession&);
void scheduleForResume();
bool isScheduledForResume() const { return m_isSuspendedWithActiveTimer || m_continueNextChunkTimer.isActive(); }
@@ -98,19 +85,34 @@ public:
void resume();
private:
- void continueNextChunkTimerFired(Timer<HTMLParserScheduler>&);
+ static const unsigned numberOfTokensBeforeCheckingForYield = 4096; // Performance optimization
+
+ void continueNextChunkTimerFired();
+
+ bool checkForYield(PumpSession& session)
+ {
+ session.processedTokens = 1;
+ session.didSeeScript = false;
+
+ // monotonicallyIncreasingTime() can be expensive. By delaying, we avoided calling
+ // monotonicallyIncreasingTime() when constructing non-yielding PumpSessions.
+ if (!session.startTime) {
+ session.startTime = monotonicallyIncreasingTime();
+ return false;
+ }
+
+ double elapsedTime = monotonicallyIncreasingTime() - session.startTime;
+ return elapsedTime > m_parserTimeLimit;
+ }
HTMLDocumentParser& m_parser;
double m_parserTimeLimit;
- int m_parserChunkSize;
- Timer<HTMLParserScheduler> m_continueNextChunkTimer;
+ Timer m_continueNextChunkTimer;
bool m_isSuspendedWithActiveTimer;
#if !ASSERT_DISABLED
bool m_suspended;
#endif
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLPreloadScanner.cpp b/Source/WebCore/html/parser/HTMLPreloadScanner.cpp
index 51c81e189..2022bd2bf 100644
--- a/Source/WebCore/html/parser/HTMLPreloadScanner.cpp
+++ b/Source/WebCore/html/parser/HTMLPreloadScanner.cpp
@@ -22,7 +22,7 @@
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
@@ -30,9 +30,14 @@
#include "HTMLNames.h"
#include "HTMLParserIdioms.h"
+#include "HTMLSrcsetParser.h"
#include "HTMLTokenizer.h"
#include "InputTypeNames.h"
#include "LinkRelAttribute.h"
+#include "MediaList.h"
+#include "MediaQueryEvaluator.h"
+#include "RenderView.h"
+#include "SizesAttributeParser.h"
#include <wtf/MainThread.h>
namespace WebCore {
@@ -56,29 +61,38 @@ TokenPreloadScanner::TagId TokenPreloadScanner::tagIdFor(const HTMLToken::DataVe
return TagId::Base;
if (tagName == templateTag)
return TagId::Template;
+ if (tagName == metaTag)
+ return TagId::Meta;
+ if (tagName == pictureTag)
+ return TagId::Picture;
+ if (tagName == sourceTag)
+ return TagId::Source;
return TagId::Unknown;
}
String TokenPreloadScanner::initiatorFor(TagId tagId)
{
switch (tagId) {
+ case TagId::Source:
case TagId::Img:
- return "img";
+ return ASCIILiteral("img");
case TagId::Input:
- return "input";
+ return ASCIILiteral("input");
case TagId::Link:
- return "link";
+ return ASCIILiteral("link");
case TagId::Script:
- return "script";
+ return ASCIILiteral("script");
case TagId::Unknown:
case TagId::Style:
case TagId::Base:
case TagId::Template:
+ case TagId::Meta:
+ case TagId::Picture:
ASSERT_NOT_REACHED();
- return "unknown";
+ return ASCIILiteral("unknown");
}
ASSERT_NOT_REACHED();
- return "unknown";
+ return ASCIILiteral("unknown");
}
class TokenPreloadScanner::StartTagScanner {
@@ -86,27 +100,43 @@ public:
explicit StartTagScanner(TagId tagId, float deviceScaleFactor = 1.0)
: m_tagId(tagId)
, m_linkIsStyleSheet(false)
+ , m_metaIsViewport(false)
, m_inputIsImage(false)
, m_deviceScaleFactor(deviceScaleFactor)
{
}
- void processAttributes(const HTMLToken::AttributeList& attributes)
+ void processAttributes(const HTMLToken::AttributeList& attributes, Document& document, Vector<bool>& pictureState)
{
ASSERT(isMainThread());
if (m_tagId >= TagId::Unknown)
return;
- for (HTMLToken::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter) {
- AtomicString attributeName(iter->name);
- String attributeValue = StringImpl::create8BitIfPossible(iter->value);
- processAttribute(attributeName, attributeValue);
+
+ for (auto& attribute : attributes) {
+ AtomicString attributeName(attribute.name);
+ String attributeValue = StringImpl::create8BitIfPossible(attribute.value);
+ processAttribute(attributeName, attributeValue, document, pictureState);
}
-
- // Resolve between src and srcSet if we have them.
- if (!m_srcSetAttribute.isEmpty()) {
- String srcMatchingScale = bestFitSourceForImageAttributes(m_deviceScaleFactor, m_urlToLoad, m_srcSetAttribute);
- setUrlToLoad(srcMatchingScale, true);
+
+ if (m_tagId == TagId::Source && !pictureState.isEmpty() && !pictureState.last() && m_mediaMatched && !m_srcSetAttribute.isEmpty()) {
+
+ auto sourceSize = SizesAttributeParser(m_sizesAttribute, document).length();
+ ImageCandidate imageCandidate = bestFitSourceForImageAttributes(m_deviceScaleFactor, m_urlToLoad, m_srcSetAttribute, sourceSize);
+ if (!imageCandidate.isEmpty()) {
+ pictureState.last() = true;
+ setUrlToLoad(imageCandidate.string.toString(), true);
+ }
+ }
+
+ // Resolve between src and srcSet if we have them and the tag is img.
+ if (m_tagId == TagId::Img && !m_srcSetAttribute.isEmpty()) {
+ auto sourceSize = SizesAttributeParser(m_sizesAttribute, document).length();
+ ImageCandidate imageCandidate = bestFitSourceForImageAttributes(m_deviceScaleFactor, m_urlToLoad, m_srcSetAttribute, sourceSize);
+ setUrlToLoad(imageCandidate.string.toString(), true);
}
+
+ if (m_metaIsViewport && !m_metaContent.isNull())
+ document.processViewport(m_metaContent, ViewportArguments::ViewportMeta);
}
std::unique_ptr<PreloadRequest> createPreloadRequest(const URL& predictedBaseURL)
@@ -114,9 +144,13 @@ public:
if (!shouldPreload())
return nullptr;
- auto request = std::make_unique<PreloadRequest>(initiatorFor(m_tagId), m_urlToLoad, predictedBaseURL, resourceType(), m_mediaAttribute);
+ auto request = std::make_unique<PreloadRequest>(initiatorFor(m_tagId), m_urlToLoad, predictedBaseURL, resourceType(), m_mediaAttribute, m_moduleScript);
+ request->setCrossOriginMode(m_crossOriginMode);
+ request->setNonce(m_nonceAttribute);
- request->setCrossOriginModeAllowsCookies(crossOriginModeAllowsCookies());
+ // According to the spec, the module tag ignores the "charset" attribute as the same to the worker's
+ // importScript. But WebKit supports the "charset" for importScript intentionally. So to be consistent,
+ // even for the module tags, we handle the "charset" attribute.
request->setCharset(charset());
return request;
}
@@ -128,38 +162,100 @@ public:
}
private:
- template<typename NameType>
- void processAttribute(const NameType& attributeName, const String& attributeValue)
+ void processImageAndScriptAttribute(const AtomicString& attributeName, const String& attributeValue)
{
- if (match(attributeName, charsetAttr))
+ if (match(attributeName, srcAttr))
+ setUrlToLoad(attributeValue);
+ else if (match(attributeName, crossoriginAttr))
+ m_crossOriginMode = stripLeadingAndTrailingHTMLSpaces(attributeValue);
+ else if (match(attributeName, charsetAttr))
m_charset = attributeValue;
+ }
- if (m_tagId == TagId::Script || m_tagId == TagId::Img) {
- if (match(attributeName, srcAttr))
- setUrlToLoad(attributeValue);
- else if (match(attributeName, srcsetAttr))
+ void processAttribute(const AtomicString& attributeName, const String& attributeValue, Document& document, const Vector<bool>& pictureState)
+ {
+ bool inPicture = !pictureState.isEmpty();
+ bool alreadyMatchedSource = inPicture && pictureState.last();
+
+ switch (m_tagId) {
+ case TagId::Img:
+ if (inPicture && alreadyMatchedSource)
+ break;
+ if (match(attributeName, srcsetAttr) && m_srcSetAttribute.isNull()) {
m_srcSetAttribute = attributeValue;
- else if (match(attributeName, crossoriginAttr) && !attributeValue.isNull())
- m_crossOriginMode = stripLeadingAndTrailingHTMLSpaces(attributeValue);
- } else if (m_tagId == TagId::Link) {
+ break;
+ }
+ if (match(attributeName, sizesAttr) && m_sizesAttribute.isNull()) {
+ m_sizesAttribute = attributeValue;
+ break;
+ }
+ processImageAndScriptAttribute(attributeName, attributeValue);
+ break;
+ case TagId::Source:
+ if (inPicture && alreadyMatchedSource)
+ break;
+ if (match(attributeName, srcsetAttr) && m_srcSetAttribute.isNull()) {
+ m_srcSetAttribute = attributeValue;
+ break;
+ }
+ if (match(attributeName, sizesAttr) && m_sizesAttribute.isNull()) {
+ m_sizesAttribute = attributeValue;
+ break;
+ }
+ if (match(attributeName, mediaAttr) && m_mediaAttribute.isNull()) {
+ m_mediaAttribute = attributeValue;
+ auto mediaSet = MediaQuerySet::create(attributeValue);
+ auto* documentElement = document.documentElement();
+ m_mediaMatched = MediaQueryEvaluator { document.printing() ? "print" : "screen", document, documentElement ? documentElement->computedStyle() : nullptr }.evaluate(mediaSet.get());
+ }
+ break;
+ case TagId::Script:
+ if (match(attributeName, typeAttr)) {
+ m_moduleScript = equalLettersIgnoringASCIICase(attributeValue, "module") ? PreloadRequest::ModuleScript::Yes : PreloadRequest::ModuleScript::No;
+ break;
+ } else if (match(attributeName, nonceAttr))
+ m_nonceAttribute = attributeValue;
+ processImageAndScriptAttribute(attributeName, attributeValue);
+ break;
+ case TagId::Link:
if (match(attributeName, hrefAttr))
setUrlToLoad(attributeValue);
else if (match(attributeName, relAttr))
m_linkIsStyleSheet = relAttributeIsStyleSheet(attributeValue);
else if (match(attributeName, mediaAttr))
m_mediaAttribute = attributeValue;
- } else if (m_tagId == TagId::Input) {
+ else if (match(attributeName, charsetAttr))
+ m_charset = attributeValue;
+ else if (match(attributeName, crossoriginAttr))
+ m_crossOriginMode = stripLeadingAndTrailingHTMLSpaces(attributeValue);
+ else if (match(attributeName, nonceAttr))
+ m_nonceAttribute = attributeValue;
+ break;
+ case TagId::Input:
if (match(attributeName, srcAttr))
setUrlToLoad(attributeValue);
else if (match(attributeName, typeAttr))
- m_inputIsImage = equalIgnoringCase(attributeValue, InputTypeNames::image());
+ m_inputIsImage = equalLettersIgnoringASCIICase(attributeValue, "image");
+ break;
+ case TagId::Meta:
+ if (match(attributeName, contentAttr))
+ m_metaContent = attributeValue;
+ else if (match(attributeName, nameAttr))
+ m_metaIsViewport = equalLettersIgnoringASCIICase(attributeValue, "viewport");
+ break;
+ case TagId::Base:
+ case TagId::Style:
+ case TagId::Template:
+ case TagId::Picture:
+ case TagId::Unknown:
+ break;
}
}
static bool relAttributeIsStyleSheet(const String& attributeValue)
{
- LinkRelAttribute rel(attributeValue);
- return rel.m_isStyleSheet && !rel.m_isAlternate && rel.m_iconType == InvalidIcon && !rel.m_isDNSPrefetch;
+ LinkRelAttribute parsedAttribute { attributeValue };
+ return parsedAttribute.isStyleSheet && !parsedAttribute.isAlternate && !parsedAttribute.iconType && !parsedAttribute.isDNSPrefetch;
}
void setUrlToLoad(const String& value, bool allowReplacement = false)
@@ -176,20 +272,30 @@ private:
const String& charset() const
{
- // FIXME: Its not clear that this if is needed, the loader probably ignores charset for image requests anyway.
- if (m_tagId == TagId::Img)
- return emptyString();
return m_charset;
}
CachedResource::Type resourceType() const
{
- if (m_tagId == TagId::Script)
+ switch (m_tagId) {
+ case TagId::Script:
return CachedResource::Script;
- if (m_tagId == TagId::Img || (m_tagId == TagId::Input && m_inputIsImage))
+ case TagId::Img:
+ case TagId::Input:
+ case TagId::Source:
+ ASSERT(m_tagId != TagId::Input || m_inputIsImage);
return CachedResource::ImageResource;
- if (m_tagId == TagId::Link && m_linkIsStyleSheet)
+ case TagId::Link:
+ ASSERT(m_linkIsStyleSheet);
return CachedResource::CSSStyleSheet;
+ case TagId::Meta:
+ case TagId::Unknown:
+ case TagId::Style:
+ case TagId::Base:
+ case TagId::Template:
+ case TagId::Picture:
+ break;
+ }
ASSERT_NOT_REACHED();
return CachedResource::RawResource;
}
@@ -199,6 +305,9 @@ private:
if (m_urlToLoad.isEmpty())
return false;
+ if (protocolIs(m_urlToLoad, "data") || protocolIs(m_urlToLoad, "about"))
+ return false;
+
if (m_tagId == TagId::Link && !m_linkIsStyleSheet)
return false;
@@ -208,98 +317,63 @@ private:
return true;
}
- bool crossOriginModeAllowsCookies()
- {
- return m_crossOriginMode.isNull() || equalIgnoringCase(m_crossOriginMode, "use-credentials");
- }
-
TagId m_tagId;
String m_urlToLoad;
String m_srcSetAttribute;
+ String m_sizesAttribute;
+ bool m_mediaMatched { true };
String m_charset;
String m_crossOriginMode;
bool m_linkIsStyleSheet;
String m_mediaAttribute;
+ String m_nonceAttribute;
+ String m_metaContent;
+ bool m_metaIsViewport;
bool m_inputIsImage;
float m_deviceScaleFactor;
+ PreloadRequest::ModuleScript m_moduleScript { PreloadRequest::ModuleScript::No };
};
TokenPreloadScanner::TokenPreloadScanner(const URL& documentURL, float deviceScaleFactor)
: m_documentURL(documentURL)
- , m_inStyle(false)
, m_deviceScaleFactor(deviceScaleFactor)
-#if ENABLE(TEMPLATE_ELEMENT)
- , m_templateCount(0)
-#endif
{
}
-TokenPreloadScanner::~TokenPreloadScanner()
-{
-}
-
-TokenPreloadScannerCheckpoint TokenPreloadScanner::createCheckpoint()
-{
- TokenPreloadScannerCheckpoint checkpoint = m_checkpoints.size();
- m_checkpoints.append(Checkpoint(m_predictedBaseElementURL, m_inStyle
-#if ENABLE(TEMPLATE_ELEMENT)
- , m_templateCount
-#endif
- ));
- return checkpoint;
-}
-
-void TokenPreloadScanner::rewindTo(TokenPreloadScannerCheckpoint checkpointIndex)
-{
- ASSERT(checkpointIndex < m_checkpoints.size()); // If this ASSERT fires, checkpointIndex is invalid.
- const Checkpoint& checkpoint = m_checkpoints[checkpointIndex];
- m_predictedBaseElementURL = checkpoint.predictedBaseElementURL;
- m_inStyle = checkpoint.inStyle;
-#if ENABLE(TEMPLATE_ELEMENT)
- m_templateCount = checkpoint.templateCount;
-#endif
- m_cssScanner.reset();
- m_checkpoints.clear();
-}
-
-void TokenPreloadScanner::scan(const HTMLToken& token, Vector<std::unique_ptr<PreloadRequest>>& requests)
+void TokenPreloadScanner::scan(const HTMLToken& token, Vector<std::unique_ptr<PreloadRequest>>& requests, Document& document)
{
switch (token.type()) {
case HTMLToken::Character:
if (!m_inStyle)
return;
- m_cssScanner.scan(token.data(), requests);
+ m_cssScanner.scan(token.characters(), requests);
return;
case HTMLToken::EndTag: {
- TagId tagId = tagIdFor(token.data());
-#if ENABLE(TEMPLATE_ELEMENT)
+ TagId tagId = tagIdFor(token.name());
if (tagId == TagId::Template) {
if (m_templateCount)
--m_templateCount;
return;
}
-#endif
if (tagId == TagId::Style) {
if (m_inStyle)
m_cssScanner.reset();
m_inStyle = false;
- }
+ } else if (tagId == TagId::Picture && !m_pictureSourceState.isEmpty())
+ m_pictureSourceState.removeLast();
+
return;
}
case HTMLToken::StartTag: {
-#if ENABLE(TEMPLATE_ELEMENT)
if (m_templateCount)
return;
-#endif
- TagId tagId = tagIdFor(token.data());
-#if ENABLE(TEMPLATE_ELEMENT)
+ TagId tagId = tagIdFor(token.name());
if (tagId == TagId::Template) {
++m_templateCount;
return;
}
-#endif
if (tagId == TagId::Style) {
m_inStyle = true;
return;
@@ -311,11 +385,15 @@ void TokenPreloadScanner::scan(const HTMLToken& token, Vector<std::unique_ptr<Pr
updatePredictedBaseURL(token);
return;
}
+ if (tagId == TagId::Picture) {
+ m_pictureSourceState.append(false);
+ return;
+ }
StartTagScanner scanner(tagId, m_deviceScaleFactor);
- scanner.processAttributes(token.attributes());
+ scanner.processAttributes(token.attributes(), document, m_pictureSourceState);
if (auto request = scanner.createPreloadRequest(m_predictedBaseElementURL))
- requests.append(std::move(request));
+ requests.append(WTFMove(request));
return;
}
@@ -324,21 +402,16 @@ void TokenPreloadScanner::scan(const HTMLToken& token, Vector<std::unique_ptr<Pr
}
}
-template<typename Token>
-void TokenPreloadScanner::updatePredictedBaseURL(const Token& token)
+void TokenPreloadScanner::updatePredictedBaseURL(const HTMLToken& token)
{
ASSERT(m_predictedBaseElementURL.isEmpty());
- if (const typename Token::Attribute* hrefAttribute = token.getAttributeItem(hrefAttr))
- m_predictedBaseElementURL = URL(m_documentURL, stripLeadingAndTrailingHTMLSpaces(hrefAttribute->value)).copy();
+ if (auto* hrefAttribute = findAttribute(token.attributes(), hrefAttr.localName().string()))
+ m_predictedBaseElementURL = URL(m_documentURL, stripLeadingAndTrailingHTMLSpaces(StringImpl::create8BitIfPossible(hrefAttribute->value))).isolatedCopy();
}
HTMLPreloadScanner::HTMLPreloadScanner(const HTMLParserOptions& options, const URL& documentURL, float deviceScaleFactor)
: m_scanner(documentURL, deviceScaleFactor)
- , m_tokenizer(std::make_unique<HTMLTokenizer>(options))
-{
-}
-
-HTMLPreloadScanner::~HTMLPreloadScanner()
+ , m_tokenizer(options)
{
}
@@ -347,24 +420,36 @@ void HTMLPreloadScanner::appendToEnd(const SegmentedString& source)
m_source.append(source);
}
-void HTMLPreloadScanner::scan(HTMLResourcePreloader* preloader, const URL& startingBaseElementURL)
+void HTMLPreloadScanner::scan(HTMLResourcePreloader& preloader, Document& document)
{
ASSERT(isMainThread()); // HTMLTokenizer::updateStateFor only works on the main thread.
+ const URL& startingBaseElementURL = document.baseElementURL();
+
// When we start scanning, our best prediction of the baseElementURL is the real one!
if (!startingBaseElementURL.isEmpty())
m_scanner.setPredictedBaseElementURL(startingBaseElementURL);
PreloadRequestStream requests;
- while (m_tokenizer->nextToken(m_source, m_token)) {
- if (m_token.type() == HTMLToken::StartTag)
- m_tokenizer->updateStateFor(AtomicString(m_token.name()));
- m_scanner.scan(m_token, requests);
- m_token.clear();
+ while (auto token = m_tokenizer.nextToken(m_source)) {
+ if (token->type() == HTMLToken::StartTag)
+ m_tokenizer.updateStateFor(AtomicString(token->name()));
+ m_scanner.scan(*token, requests, document);
}
- preloader->preload(std::move(requests));
+ preloader.preload(WTFMove(requests));
+}
+
+bool testPreloadScannerViewportSupport(Document* document)
+{
+ ASSERT(document);
+ HTMLParserOptions options(*document);
+ HTMLPreloadScanner scanner(options, document->url());
+ HTMLResourcePreloader preloader(*document);
+ scanner.appendToEnd(String("<meta name=viewport content='width=400'>"));
+ scanner.scan(preloader, *document);
+ return (document->viewportArguments().width == 400);
}
}
diff --git a/Source/WebCore/html/parser/HTMLPreloadScanner.h b/Source/WebCore/html/parser/HTMLPreloadScanner.h
index 963c6b92e..8181da74a 100644
--- a/Source/WebCore/html/parser/HTMLPreloadScanner.h
+++ b/Source/WebCore/html/parser/HTMLPreloadScanner.h
@@ -24,42 +24,24 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLPreloadScanner_h
-#define HTMLPreloadScanner_h
+#pragma once
#include "CSSPreloadScanner.h"
-#include "HTMLToken.h"
+#include "HTMLTokenizer.h"
#include "SegmentedString.h"
-#include <wtf/Vector.h>
namespace WebCore {
-typedef size_t TokenPreloadScannerCheckpoint;
-
-class HTMLParserOptions;
-class HTMLTokenizer;
-class SegmentedString;
-
class TokenPreloadScanner {
- WTF_MAKE_NONCOPYABLE(TokenPreloadScanner); WTF_MAKE_FAST_ALLOCATED;
+ WTF_MAKE_NONCOPYABLE(TokenPreloadScanner);
public:
explicit TokenPreloadScanner(const URL& documentURL, float deviceScaleFactor = 1.0);
- ~TokenPreloadScanner();
- void scan(const HTMLToken&, PreloadRequestStream& requests);
+ void scan(const HTMLToken&, PreloadRequestStream&, Document&);
void setPredictedBaseElementURL(const URL& url) { m_predictedBaseElementURL = url; }
-
- // A TokenPreloadScannerCheckpoint is valid until the next call to rewindTo,
- // at which point all outstanding checkpoints are invalidated.
- TokenPreloadScannerCheckpoint createCheckpoint();
- void rewindTo(TokenPreloadScannerCheckpoint);
-
- bool isSafeToSendToAnotherThread()
- {
- return m_documentURL.isSafeToSendToAnotherThread()
- && m_predictedBaseElementURL.isSafeToSendToAnotherThread();
- }
+
+ bool inPicture() { return !m_pictureSourceState.isEmpty(); }
private:
enum class TagId {
@@ -68,12 +50,15 @@ private:
Input,
Link,
Script,
+ Meta,
+ Source,
// These tags are not scanned by the StartTagScanner.
Unknown,
Style,
Base,
Template,
+ Picture
};
class StartTagScanner;
@@ -82,59 +67,34 @@ private:
static String initiatorFor(TagId);
- template<typename Token>
- void updatePredictedBaseURL(const Token&);
-
- struct Checkpoint {
- Checkpoint(const URL& predictedBaseElementURL, bool inStyle
-#if ENABLE(TEMPLATE_ELEMENT)
- , size_t templateCount
-#endif
- )
- : predictedBaseElementURL(predictedBaseElementURL)
- , inStyle(inStyle)
-#if ENABLE(TEMPLATE_ELEMENT)
- , templateCount(templateCount)
-#endif
- {
- }
-
- URL predictedBaseElementURL;
- bool inStyle;
-#if ENABLE(TEMPLATE_ELEMENT)
- size_t templateCount;
-#endif
- };
+ void updatePredictedBaseURL(const HTMLToken&);
CSSPreloadScanner m_cssScanner;
const URL m_documentURL;
- URL m_predictedBaseElementURL;
- bool m_inStyle;
- float m_deviceScaleFactor;
+ const float m_deviceScaleFactor { 1 };
-#if ENABLE(TEMPLATE_ELEMENT)
- size_t m_templateCount;
-#endif
+ URL m_predictedBaseElementURL;
+ bool m_inStyle { false };
+
+ Vector<bool> m_pictureSourceState;
- Vector<Checkpoint> m_checkpoints;
+ unsigned m_templateCount { 0 };
};
class HTMLPreloadScanner {
- WTF_MAKE_NONCOPYABLE(HTMLPreloadScanner); WTF_MAKE_FAST_ALLOCATED;
+ WTF_MAKE_FAST_ALLOCATED;
public:
HTMLPreloadScanner(const HTMLParserOptions&, const URL& documentURL, float deviceScaleFactor = 1.0);
- ~HTMLPreloadScanner();
void appendToEnd(const SegmentedString&);
- void scan(HTMLResourcePreloader*, const URL& documentBaseElementURL);
+ void scan(HTMLResourcePreloader&, Document&);
private:
TokenPreloadScanner m_scanner;
SegmentedString m_source;
- HTMLToken m_token;
- std::unique_ptr<HTMLTokenizer> m_tokenizer;
+ HTMLTokenizer m_tokenizer;
};
-}
+WEBCORE_EXPORT bool testPreloadScannerViewportSupport(Document*);
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLResourcePreloader.cpp b/Source/WebCore/html/parser/HTMLResourcePreloader.cpp
index cfd2342b2..623662431 100644
--- a/Source/WebCore/html/parser/HTMLResourcePreloader.cpp
+++ b/Source/WebCore/html/parser/HTMLResourcePreloader.cpp
@@ -20,7 +20,7 @@
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
@@ -35,54 +35,56 @@
namespace WebCore {
-bool PreloadRequest::isSafeToSendToAnotherThread() const
-{
- return m_initiator.isSafeToSendToAnotherThread()
- && m_charset.isSafeToSendToAnotherThread()
- && m_resourceURL.isSafeToSendToAnotherThread()
- && m_mediaAttribute.isSafeToSendToAnotherThread()
- && m_baseURL.isSafeToSendToAnotherThread();
-}
-
URL PreloadRequest::completeURL(Document& document)
{
- return document.completeURL(m_resourceURL, m_baseURL.isEmpty() ? document.url() : m_baseURL);
+ return document.completeURL(m_resourceURL, m_baseURL.isEmpty() ? document.baseURL() : m_baseURL);
}
CachedResourceRequest PreloadRequest::resourceRequest(Document& document)
{
ASSERT(isMainThread());
- CachedResourceRequest request(ResourceRequest(completeURL(document)));
- request.setInitiator(m_initiator);
- // FIXME: It's possible CORS should work for other request types?
- if (m_resourceType == CachedResource::Script)
- request.mutableResourceRequest().setAllowCookies(m_crossOriginModeAllowsCookies);
+ bool skipContentSecurityPolicyCheck = false;
+ if (m_resourceType == CachedResource::Type::Script)
+ skipContentSecurityPolicyCheck = document.contentSecurityPolicy()->allowScriptWithNonce(m_nonceAttribute);
+ else if (m_resourceType == CachedResource::Type::CSSStyleSheet)
+ skipContentSecurityPolicyCheck = document.contentSecurityPolicy()->allowStyleWithNonce(m_nonceAttribute);
+
+ ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions();
+ if (skipContentSecurityPolicyCheck)
+ options.contentSecurityPolicyImposition = ContentSecurityPolicyImposition::SkipPolicyCheck;
+
+ CachedResourceRequest request { completeURL(document), options };
+ request.setInitiator(m_initiator);
+ String crossOriginMode = m_crossOriginMode;
+ if (m_moduleScript == ModuleScript::Yes) {
+ if (crossOriginMode.isNull())
+ crossOriginMode = ASCIILiteral("omit");
+ }
+ request.setAsPotentiallyCrossOrigin(crossOriginMode, document);
return request;
}
void HTMLResourcePreloader::preload(PreloadRequestStream requests)
{
for (auto& request : requests)
- preload(std::move(request));
+ preload(WTFMove(request));
}
-static bool mediaAttributeMatches(Frame* frame, RenderStyle* renderStyle, const String& attributeValue)
+static bool mediaAttributeMatches(Document& document, const RenderStyle* renderStyle, const String& attributeValue)
{
- RefPtr<MediaQuerySet> mediaQueries = MediaQuerySet::createAllowingDescriptionSyntax(attributeValue);
- MediaQueryEvaluator mediaQueryEvaluator("screen", frame, renderStyle);
- return mediaQueryEvaluator.eval(mediaQueries.get());
+ auto mediaQueries = MediaQuerySet::create(attributeValue);
+ return MediaQueryEvaluator { "screen", document, renderStyle }.evaluate(mediaQueries.get());
}
void HTMLResourcePreloader::preload(std::unique_ptr<PreloadRequest> preload)
{
ASSERT(m_document.frame());
ASSERT(m_document.renderView());
- if (!preload->media().isEmpty() && !mediaAttributeMatches(m_document.frame(), &m_document.renderView()->style(), preload->media()))
+ if (!preload->media().isEmpty() && !mediaAttributeMatches(m_document, &m_document.renderView()->style(), preload->media()))
return;
- CachedResourceRequest request = preload->resourceRequest(m_document);
- m_document.cachedResourceLoader()->preload(preload->resourceType(), request, preload->charset());
+ m_document.cachedResourceLoader().preload(preload->resourceType(), preload->resourceRequest(m_document));
}
diff --git a/Source/WebCore/html/parser/HTMLResourcePreloader.h b/Source/WebCore/html/parser/HTMLResourcePreloader.h
index f93a093bd..cd10f85de 100644
--- a/Source/WebCore/html/parser/HTMLResourcePreloader.h
+++ b/Source/WebCore/html/parser/HTMLResourcePreloader.h
@@ -20,11 +20,10 @@
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLResourcePreloader_h
-#define HTMLResourcePreloader_h
+#pragma once
#include "CachedResource.h"
#include "CachedResourceRequest.h"
@@ -32,25 +31,29 @@
namespace WebCore {
class PreloadRequest {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- PreloadRequest(const String& initiator, const String& resourceURL, const URL& baseURL, CachedResource::Type resourceType, const String& mediaAttribute)
+ enum class ModuleScript {
+ Yes,
+ No,
+ };
+ PreloadRequest(const String& initiator, const String& resourceURL, const URL& baseURL, CachedResource::Type resourceType, const String& mediaAttribute, ModuleScript moduleScript)
: m_initiator(initiator)
- , m_resourceURL(resourceURL.isolatedCopy())
- , m_baseURL(baseURL.copy())
+ , m_resourceURL(resourceURL)
+ , m_baseURL(baseURL.isolatedCopy())
, m_resourceType(resourceType)
- , m_mediaAttribute(mediaAttribute.isolatedCopy())
- , m_crossOriginModeAllowsCookies(false)
+ , m_mediaAttribute(mediaAttribute)
+ , m_moduleScript(moduleScript)
{
}
- bool isSafeToSendToAnotherThread() const;
-
CachedResourceRequest resourceRequest(Document&);
const String& charset() const { return m_charset; }
const String& media() const { return m_mediaAttribute; }
void setCharset(const String& charset) { m_charset = charset.isolatedCopy(); }
- void setCrossOriginModeAllowsCookies(bool allowsCookies) { m_crossOriginModeAllowsCookies = allowsCookies; }
+ void setCrossOriginMode(const String& mode) { m_crossOriginMode = mode; }
+ void setNonce(const String& nonce) { m_nonceAttribute = nonce; }
CachedResource::Type resourceType() const { return m_resourceType; }
private:
@@ -62,7 +65,9 @@ private:
String m_charset;
CachedResource::Type m_resourceType;
String m_mediaAttribute;
- bool m_crossOriginModeAllowsCookies;
+ String m_crossOriginMode;
+ String m_nonceAttribute;
+ ModuleScript m_moduleScript;
};
typedef Vector<std::unique_ptr<PreloadRequest>> PreloadRequestStream;
@@ -86,6 +91,4 @@ private:
WeakPtrFactory<HTMLResourcePreloader> m_weakFactory;
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLScriptRunner.cpp b/Source/WebCore/html/parser/HTMLScriptRunner.cpp
index 41e725f60..1a38b1323 100644
--- a/Source/WebCore/html/parser/HTMLScriptRunner.cpp
+++ b/Source/WebCore/html/parser/HTMLScriptRunner.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2010-2017 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,19 +27,18 @@
#include "config.h"
#include "HTMLScriptRunner.h"
-#include "Attribute.h"
-#include "CachedScript.h"
-#include "CachedResourceLoader.h"
#include "Element.h"
#include "Event.h"
+#include "EventNames.h"
#include "Frame.h"
#include "HTMLInputStream.h"
#include "HTMLNames.h"
#include "HTMLScriptRunnerHost.h"
#include "IgnoreDestructiveWriteCountIncrementer.h"
+#include "InlineClassicScript.h"
+#include "Microtasks.h"
#include "MutationObserver.h"
#include "NestingLevelIncrementer.h"
-#include "NotImplemented.h"
#include "ScriptElement.h"
#include "ScriptSourceCode.h"
@@ -57,19 +57,21 @@ HTMLScriptRunner::HTMLScriptRunner(Document& document, HTMLScriptRunnerHost& hos
HTMLScriptRunner::~HTMLScriptRunner()
{
// FIXME: Should we be passed a "done loading/parsing" callback sooner than destruction?
- if (m_parserBlockingScript.cachedScript() && m_parserBlockingScript.watchingForLoad())
- stopWatchingForLoad(m_parserBlockingScript);
+ if (m_parserBlockingScript) {
+ if (m_parserBlockingScript->watchingForLoad())
+ stopWatchingForLoad(*m_parserBlockingScript);
+ }
while (!m_scriptsToExecuteAfterParsing.isEmpty()) {
- PendingScript pendingScript = m_scriptsToExecuteAfterParsing.takeFirst();
- if (pendingScript.cachedScript() && pendingScript.watchingForLoad())
+ auto pendingScript = m_scriptsToExecuteAfterParsing.takeFirst();
+ if (pendingScript->watchingForLoad())
stopWatchingForLoad(pendingScript);
}
}
void HTMLScriptRunner::detach()
{
- m_document = 0;
+ m_document = nullptr;
}
static URL documentURLForScriptExecution(Document* document)
@@ -81,22 +83,11 @@ static URL documentURLForScriptExecution(Document* document)
return document->frame()->document()->url();
}
-inline PassRefPtr<Event> createScriptLoadEvent()
+inline Ref<Event> createScriptLoadEvent()
{
return Event::create(eventNames().loadEvent, false, false);
}
-ScriptSourceCode HTMLScriptRunner::sourceFromPendingScript(const PendingScript& script, bool& errorOccurred) const
-{
- if (script.cachedScript()) {
- errorOccurred = script.cachedScript()->errorOccurred();
- ASSERT(script.cachedScript()->isLoaded());
- return ScriptSourceCode(script.cachedScript());
- }
- errorOccurred = false;
- return ScriptSourceCode(script.element()->textContent(), documentURLForScriptExecution(m_document), script.startingPosition());
-}
-
bool HTMLScriptRunner::isPendingScriptReady(const PendingScript& script)
{
if (!m_document)
@@ -104,46 +95,23 @@ bool HTMLScriptRunner::isPendingScriptReady(const PendingScript& script)
m_hasScriptsWaitingForStylesheets = !m_document->haveStylesheetsLoaded();
if (m_hasScriptsWaitingForStylesheets)
return false;
- if (script.cachedScript() && !script.cachedScript()->isLoaded())
+ if (script.needsLoading() && !script.isLoaded())
return false;
return true;
}
-void HTMLScriptRunner::executeParsingBlockingScript()
-{
- ASSERT(m_document);
- ASSERT(!isExecutingScript());
- ASSERT(m_document->haveStylesheetsLoaded());
- ASSERT(isPendingScriptReady(m_parserBlockingScript));
-
- InsertionPointRecord insertionPointRecord(m_host.inputStream());
- executePendingScriptAndDispatchEvent(m_parserBlockingScript);
-}
-
void HTMLScriptRunner::executePendingScriptAndDispatchEvent(PendingScript& pendingScript)
{
- bool errorOccurred = false;
- ScriptSourceCode sourceCode = sourceFromPendingScript(pendingScript, errorOccurred);
-
// Stop watching loads before executeScript to prevent recursion if the script reloads itself.
- if (pendingScript.cachedScript() && pendingScript.watchingForLoad())
+ if (pendingScript.watchingForLoad())
stopWatchingForLoad(pendingScript);
if (!isExecutingScript())
- MutationObserver::deliverAllMutations();
+ MicrotaskQueue::mainThreadQueue().performMicrotaskCheckpoint();
- // Clear the pending script before possible rentrancy from executeScript()
- RefPtr<Element> element = pendingScript.releaseElementAndClear();
- if (ScriptElement* scriptElement = toScriptElementIfPossible(element.get())) {
+ {
NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel);
- IgnoreDestructiveWriteCountIncrementer ignoreDestructiveWriteCountIncrementer(m_document);
- if (errorOccurred)
- scriptElement->dispatchErrorEvent();
- else {
- ASSERT(isExecutingScript());
- scriptElement->executeScript(sourceCode);
- element->dispatchEvent(createScriptLoadEvent());
- }
+ pendingScript.element().executePendingScript(pendingScript);
}
ASSERT(!isExecutingScript());
}
@@ -151,28 +119,25 @@ void HTMLScriptRunner::executePendingScriptAndDispatchEvent(PendingScript& pendi
void HTMLScriptRunner::watchForLoad(PendingScript& pendingScript)
{
ASSERT(!pendingScript.watchingForLoad());
- m_host.watchForLoad(pendingScript.cachedScript());
- pendingScript.setWatchingForLoad(true);
+ m_host.watchForLoad(pendingScript);
}
void HTMLScriptRunner::stopWatchingForLoad(PendingScript& pendingScript)
{
ASSERT(pendingScript.watchingForLoad());
- m_host.stopWatchingForLoad(pendingScript.cachedScript());
- pendingScript.setWatchingForLoad(false);
+ m_host.stopWatchingForLoad(pendingScript);
}
// This function should match 10.2.5.11 "An end tag whose tag name is 'script'"
// Script handling lives outside the tree builder to keep the each class simple.
-void HTMLScriptRunner::execute(PassRefPtr<Element> scriptElement, const TextPosition& scriptStartPosition)
+void HTMLScriptRunner::execute(Ref<ScriptElement>&& element, const TextPosition& scriptStartPosition)
{
- ASSERT(scriptElement);
// FIXME: If scripting is disabled, always just return.
bool hadPreloadScanner = m_host.hasPreloadScanner();
// Try to execute the script given to us.
- runScript(scriptElement.get(), scriptStartPosition);
+ runScript(element.get(), scriptStartPosition);
if (hasParserBlockingScript()) {
if (isExecutingScript())
@@ -186,21 +151,26 @@ void HTMLScriptRunner::execute(PassRefPtr<Element> scriptElement, const TextPosi
bool HTMLScriptRunner::hasParserBlockingScript() const
{
- return !!m_parserBlockingScript.element();
+ return !!m_parserBlockingScript;
}
void HTMLScriptRunner::executeParsingBlockingScripts()
{
- while (hasParserBlockingScript() && isPendingScriptReady(m_parserBlockingScript))
- executeParsingBlockingScript();
+ while (hasParserBlockingScript() && isPendingScriptReady(*m_parserBlockingScript)) {
+ ASSERT(m_document);
+ ASSERT(!isExecutingScript());
+ ASSERT(m_document->haveStylesheetsLoaded());
+ InsertionPointRecord insertionPointRecord(m_host.inputStream());
+ executePendingScriptAndDispatchEvent(m_parserBlockingScript.releaseNonNull().get());
+ }
}
-void HTMLScriptRunner::executeScriptsWaitingForLoad(CachedResource* cachedScript)
+void HTMLScriptRunner::executeScriptsWaitingForLoad(PendingScript& pendingScript)
{
ASSERT(!isExecutingScript());
ASSERT(hasParserBlockingScript());
- ASSERT_UNUSED(cachedScript, m_parserBlockingScript.cachedScript() == cachedScript);
- ASSERT(m_parserBlockingScript.cachedScript()->isLoaded());
+ ASSERT_UNUSED(pendingScript, m_parserBlockingScript.get() == &pendingScript);
+ ASSERT(m_parserBlockingScript->isLoaded());
executeParsingBlockingScripts();
}
@@ -220,13 +190,12 @@ bool HTMLScriptRunner::executeScriptsWaitingForParsing()
while (!m_scriptsToExecuteAfterParsing.isEmpty()) {
ASSERT(!isExecutingScript());
ASSERT(!hasParserBlockingScript());
- ASSERT(m_scriptsToExecuteAfterParsing.first().cachedScript());
- if (!m_scriptsToExecuteAfterParsing.first().cachedScript()->isLoaded()) {
+ ASSERT(m_scriptsToExecuteAfterParsing.first()->needsLoading());
+ if (!m_scriptsToExecuteAfterParsing.first()->isLoaded()) {
watchForLoad(m_scriptsToExecuteAfterParsing.first());
return false;
}
- PendingScript first = m_scriptsToExecuteAfterParsing.takeFirst();
- executePendingScriptAndDispatchEvent(first);
+ executePendingScriptAndDispatchEvent(m_scriptsToExecuteAfterParsing.takeFirst().get());
// FIXME: What is this m_document check for?
if (!m_document)
return false;
@@ -234,89 +203,64 @@ bool HTMLScriptRunner::executeScriptsWaitingForParsing()
return true;
}
-void HTMLScriptRunner::requestParsingBlockingScript(Element* element)
+static Ref<PendingScript> requestPendingScript(ScriptElement& scriptElement)
{
- if (!requestPendingScript(m_parserBlockingScript, element))
- return;
-
- ASSERT(m_parserBlockingScript.cachedScript());
-
- // We only care about a load callback if cachedScript is not already
- // in the cache. Callers will attempt to run the m_parserBlockingScript
- // if possible before returning control to the parser.
- if (!m_parserBlockingScript.cachedScript()->isLoaded())
- watchForLoad(m_parserBlockingScript);
+ ASSERT(scriptElement.willBeParserExecuted());
+ ASSERT(scriptElement.loadableScript());
+ return PendingScript::create(scriptElement, *scriptElement.loadableScript());
}
-void HTMLScriptRunner::requestDeferredScript(Element* element)
+void HTMLScriptRunner::requestParsingBlockingScript(ScriptElement& scriptElement)
{
- PendingScript pendingScript;
- if (!requestPendingScript(pendingScript, element))
- return;
+ ASSERT(!m_parserBlockingScript);
+ m_parserBlockingScript = requestPendingScript(scriptElement);
+ ASSERT(m_parserBlockingScript->needsLoading());
- ASSERT(pendingScript.cachedScript());
- m_scriptsToExecuteAfterParsing.append(pendingScript);
+ // We only care about a load callback if LoadableScript is not already
+ // in the cache. Callers will attempt to run the m_parserBlockingScript
+ // if possible before returning control to the parser.
+ if (!m_parserBlockingScript->isLoaded())
+ watchForLoad(*m_parserBlockingScript);
}
-bool HTMLScriptRunner::requestPendingScript(PendingScript& pendingScript, Element* script) const
+void HTMLScriptRunner::requestDeferredScript(ScriptElement& scriptElement)
{
- ASSERT(!pendingScript.element());
- pendingScript.setElement(script);
- // This should correctly return 0 for empty or invalid srcValues.
- CachedScript* cachedScript = toScriptElementIfPossible(script)->cachedScript().get();
- if (!cachedScript) {
- notImplemented(); // Dispatch error event.
- return false;
- }
- pendingScript.setCachedScript(cachedScript);
- return true;
+ auto pendingScript = requestPendingScript(scriptElement);
+ ASSERT(pendingScript->needsLoading());
+ m_scriptsToExecuteAfterParsing.append(WTFMove(pendingScript));
}
// This method is meant to match the HTML5 definition of "running a script"
// http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#running-a-script
-void HTMLScriptRunner::runScript(Element* script, const TextPosition& scriptStartPosition)
+void HTMLScriptRunner::runScript(ScriptElement& scriptElement, const TextPosition& scriptStartPosition)
{
ASSERT(m_document);
ASSERT(!hasParserBlockingScript());
- {
- ScriptElement* scriptElement = toScriptElementIfPossible(script);
-
- // This contains both and ASSERTION and a null check since we should not
- // be getting into the case of a null script element, but seem to be from
- // time to time. The assertion is left in to help find those cases and
- // is being tracked by <https://bugs.webkit.org/show_bug.cgi?id=60559>.
- ASSERT(scriptElement);
- if (!scriptElement)
- return;
-
- // FIXME: This may be too agressive as we always deliver mutations at
- // every script element, even if it's not ready to execute yet. There's
- // unfortuantely no obvious way to tell if prepareScript is going to
- // execute the script from out here.
- if (!isExecutingScript())
- MutationObserver::deliverAllMutations();
- InsertionPointRecord insertionPointRecord(m_host.inputStream());
- NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel);
+ // FIXME: This may be too agressive as we always deliver mutations at
+ // every script element, even if it's not ready to execute yet. There's
+ // unfortunately no obvious way to tell if prepareScript is going to
+ // execute the script before calling it.
+ if (!isExecutingScript())
+ MicrotaskQueue::mainThreadQueue().performMicrotaskCheckpoint();
- scriptElement->prepareScript(scriptStartPosition);
-
- if (!scriptElement->willBeParserExecuted())
- return;
-
- if (scriptElement->willExecuteWhenDocumentFinishedParsing())
- requestDeferredScript(script);
- else if (scriptElement->readyToBeParserExecuted()) {
- if (m_scriptNestingLevel == 1) {
- m_parserBlockingScript.setElement(script);
- m_parserBlockingScript.setStartingPosition(scriptStartPosition);
- } else {
- ScriptSourceCode sourceCode(script->textContent(), documentURLForScriptExecution(m_document), scriptStartPosition);
- scriptElement->executeScript(sourceCode);
- }
- } else
- requestParsingBlockingScript(script);
- }
+ InsertionPointRecord insertionPointRecord(m_host.inputStream());
+ NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel);
+
+ scriptElement.prepareScript(scriptStartPosition);
+
+ if (!scriptElement.willBeParserExecuted())
+ return;
+
+ if (scriptElement.willExecuteWhenDocumentFinishedParsing())
+ requestDeferredScript(scriptElement);
+ else if (scriptElement.readyToBeParserExecuted()) {
+ if (m_scriptNestingLevel == 1)
+ m_parserBlockingScript = PendingScript::create(scriptElement, scriptStartPosition);
+ else
+ scriptElement.executeClassicScript(ScriptSourceCode(scriptElement.element().textContent(), documentURLForScriptExecution(m_document), scriptStartPosition, JSC::SourceProviderSourceType::Program, InlineClassicScript::create(scriptElement)));
+ } else
+ requestParsingBlockingScript(scriptElement);
}
}
diff --git a/Source/WebCore/html/parser/HTMLScriptRunner.h b/Source/WebCore/html/parser/HTMLScriptRunner.h
index 45bf8d032..c86747d91 100644
--- a/Source/WebCore/html/parser/HTMLScriptRunner.h
+++ b/Source/WebCore/html/parser/HTMLScriptRunner.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2010-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,8 +24,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLScriptRunner_h
-#define HTMLScriptRunner_h
+#pragma once
#include "PendingScript.h"
#include <wtf/Deque.h>
@@ -32,16 +32,13 @@
namespace WebCore {
-class CachedResource;
-class CachedScript;
class Document;
-class Element;
class Frame;
class HTMLScriptRunnerHost;
class ScriptSourceCode;
class HTMLScriptRunner {
- WTF_MAKE_NONCOPYABLE(HTMLScriptRunner); WTF_MAKE_FAST_ALLOCATED;
+ WTF_MAKE_FAST_ALLOCATED;
public:
HTMLScriptRunner(Document&, HTMLScriptRunnerHost&);
~HTMLScriptRunner();
@@ -49,9 +46,9 @@ public:
void detach();
// Processes the passed in script and any pending scripts if possible.
- void execute(PassRefPtr<Element> scriptToProcess, const TextPosition& scriptStartPosition);
+ void execute(Ref<ScriptElement>&&, const TextPosition& scriptStartPosition);
- void executeScriptsWaitingForLoad(CachedResource*);
+ void executeScriptsWaitingForLoad(PendingScript&);
bool hasScriptsWaitingForStylesheets() const { return m_hasScriptsWaitingForStylesheets; }
void executeScriptsWaitingForStylesheets();
bool executeScriptsWaitingForParsing();
@@ -62,26 +59,22 @@ public:
private:
Frame* frame() const;
- void executeParsingBlockingScript();
void executePendingScriptAndDispatchEvent(PendingScript&);
void executeParsingBlockingScripts();
- void requestParsingBlockingScript(Element*);
- void requestDeferredScript(Element*);
- bool requestPendingScript(PendingScript&, Element*) const;
+ void requestParsingBlockingScript(ScriptElement&);
+ void requestDeferredScript(ScriptElement&);
- void runScript(Element*, const TextPosition& scriptStartPosition);
+ void runScript(ScriptElement&, const TextPosition& scriptStartPosition);
- // Helpers for dealing with HTMLScriptRunnerHost
void watchForLoad(PendingScript&);
void stopWatchingForLoad(PendingScript&);
bool isPendingScriptReady(const PendingScript&);
- ScriptSourceCode sourceFromPendingScript(const PendingScript&, bool& errorOccurred) const;
Document* m_document;
HTMLScriptRunnerHost& m_host;
- PendingScript m_parserBlockingScript;
- Deque<PendingScript> m_scriptsToExecuteAfterParsing; // http://www.whatwg.org/specs/web-apps/current-work/#list-of-scripts-that-will-execute-when-the-document-has-finished-parsing
+ RefPtr<PendingScript> m_parserBlockingScript;
+ Deque<Ref<PendingScript>> m_scriptsToExecuteAfterParsing; // http://www.whatwg.org/specs/web-apps/current-work/#list-of-scripts-that-will-execute-when-the-document-has-finished-parsing
unsigned m_scriptNestingLevel;
// We only want stylesheet loads to trigger script execution if script
@@ -91,6 +84,4 @@ private:
bool m_hasScriptsWaitingForStylesheets;
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLScriptRunnerHost.h b/Source/WebCore/html/parser/HTMLScriptRunnerHost.h
index 1f2289657..0f15f537c 100644
--- a/Source/WebCore/html/parser/HTMLScriptRunnerHost.h
+++ b/Source/WebCore/html/parser/HTMLScriptRunnerHost.h
@@ -23,34 +23,26 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLScriptRunnerHost_h
-#define HTMLScriptRunnerHost_h
-
-#include <wtf/Forward.h>
+#pragma once
namespace WebCore {
-class CachedResource;
-class Element;
class HTMLInputStream;
-class ScriptSourceCode;
+class PendingScript;
class HTMLScriptRunnerHost {
public:
virtual ~HTMLScriptRunnerHost() { }
// Implementors should call cachedResource->addClient() here or soon after.
- virtual void watchForLoad(CachedResource*) = 0;
+ virtual void watchForLoad(PendingScript&) = 0;
// Implementors must call cachedResource->removeClient() immediately.
- virtual void stopWatchingForLoad(CachedResource*) = 0;
+ virtual void stopWatchingForLoad(PendingScript&) = 0;
virtual HTMLInputStream& inputStream() = 0;
virtual bool hasPreloadScanner() const = 0;
- virtual void appendCurrentInputStreamToPreloadScannerAndScan() = 0;
-
+ virtual void appendCurrentInputStreamToPreloadScannerAndScan() = 0;
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLSourceTracker.cpp b/Source/WebCore/html/parser/HTMLSourceTracker.cpp
index bf1a8c466..22dba90a5 100644
--- a/Source/WebCore/html/parser/HTMLSourceTracker.cpp
+++ b/Source/WebCore/html/parser/HTMLSourceTracker.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Adam Barth. All Rights Reserved.
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,58 +26,60 @@
#include "config.h"
#include "HTMLSourceTracker.h"
+
#include "HTMLTokenizer.h"
#include <wtf/text/StringBuilder.h>
namespace WebCore {
-HTMLSourceTracker::HTMLSourceTracker()
+void HTMLSourceTracker::startToken(SegmentedString& currentInput, HTMLTokenizer& tokenizer)
{
-}
-
-void HTMLSourceTracker::start(SegmentedString& currentInput, HTMLTokenizer* tokenizer, HTMLToken& token)
-{
- if (token.type() == HTMLToken::Uninitialized) {
- m_previousSource.clear();
- if (tokenizer->numberOfBufferedCharacters())
- m_previousSource = tokenizer->bufferedCharacters();
+ if (!m_started) {
+ if (tokenizer.numberOfBufferedCharacters())
+ m_previousSource = tokenizer.bufferedCharacters();
+ else
+ m_previousSource.clear();
+ m_started = true;
} else
m_previousSource.append(m_currentSource);
m_currentSource = currentInput;
- token.setBaseOffset(m_currentSource.numberOfCharactersConsumed() - m_previousSource.length());
+ m_tokenStart = m_currentSource.numberOfCharactersConsumed() - m_previousSource.length();
+ tokenizer.setTokenAttributeBaseOffset(m_tokenStart);
}
-void HTMLSourceTracker::end(SegmentedString& currentInput, HTMLTokenizer* tokenizer, HTMLToken& token)
+void HTMLSourceTracker::endToken(SegmentedString& currentInput, HTMLTokenizer& tokenizer)
{
- m_cachedSourceForToken = String();
+ ASSERT(m_started);
+ m_started = false;
- // FIXME: This work should really be done by the HTMLTokenizer.
- token.end(currentInput.numberOfCharactersConsumed() - tokenizer->numberOfBufferedCharacters());
+ m_tokenEnd = currentInput.numberOfCharactersConsumed() - tokenizer.numberOfBufferedCharacters();
+ m_cachedSourceForToken = String();
}
-String HTMLSourceTracker::sourceForToken(const HTMLToken& token)
+String HTMLSourceTracker::source(const HTMLToken& token)
{
+ ASSERT(!m_started);
+
if (token.type() == HTMLToken::EndOfFile)
return String(); // Hides the null character we use to mark the end of file.
if (!m_cachedSourceForToken.isEmpty())
return m_cachedSourceForToken;
- ASSERT(!token.startIndex());
- size_t length = static_cast<size_t>(token.endIndex() - token.startIndex());
+ unsigned length = m_tokenEnd - m_tokenStart;
StringBuilder source;
source.reserveCapacity(length);
- size_t i = 0;
+ unsigned i = 0;
for ( ; i < length && !m_previousSource.isEmpty(); ++i) {
- source.append(m_previousSource.currentChar());
+ source.append(m_previousSource.currentCharacter());
m_previousSource.advance();
}
for ( ; i < length; ++i) {
ASSERT(!m_currentSource.isEmpty());
- source.append(m_currentSource.currentChar());
+ source.append(m_currentSource.currentCharacter());
m_currentSource.advance();
}
@@ -84,4 +87,9 @@ String HTMLSourceTracker::sourceForToken(const HTMLToken& token)
return m_cachedSourceForToken;
}
+String HTMLSourceTracker::source(const HTMLToken& token, unsigned attributeStart, unsigned attributeEnd)
+{
+ return source(token).substring(attributeStart, attributeEnd - attributeStart);
+}
+
}
diff --git a/Source/WebCore/html/parser/HTMLSourceTracker.h b/Source/WebCore/html/parser/HTMLSourceTracker.h
index 7f0378b8f..3a24cf0fc 100644
--- a/Source/WebCore/html/parser/HTMLSourceTracker.h
+++ b/Source/WebCore/html/parser/HTMLSourceTracker.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010 Adam Barth. All Rights Reserved.
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,36 +24,36 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLSourceTracker_h
-#define HTMLSourceTracker_h
+#pragma once
-#include "HTMLToken.h"
#include "SegmentedString.h"
namespace WebCore {
+class HTMLToken;
class HTMLTokenizer;
class HTMLSourceTracker {
WTF_MAKE_NONCOPYABLE(HTMLSourceTracker);
public:
- HTMLSourceTracker();
+ HTMLSourceTracker() = default;
- // FIXME: Once we move "end" into HTMLTokenizer, rename "start" to
- // something that makes it obvious that this method can be called multiple
- // times.
- void start(SegmentedString&, HTMLTokenizer*, HTMLToken&);
- void end(SegmentedString&, HTMLTokenizer*, HTMLToken&);
+ void startToken(SegmentedString&, HTMLTokenizer&);
+ void endToken(SegmentedString&, HTMLTokenizer&);
- String sourceForToken(const HTMLToken&);
+ String source(const HTMLToken&);
+ String source(const HTMLToken&, unsigned attributeStart, unsigned attributeEnd);
private:
+ bool m_started { false };
+
+ unsigned m_tokenStart;
+ unsigned m_tokenEnd;
+
SegmentedString m_previousSource;
SegmentedString m_currentSource;
String m_cachedSourceForToken;
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLSrcsetParser.cpp b/Source/WebCore/html/parser/HTMLSrcsetParser.cpp
new file mode 100644
index 000000000..66a9864c2
--- /dev/null
+++ b/Source/WebCore/html/parser/HTMLSrcsetParser.cpp
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "HTMLSrcsetParser.h"
+
+#include "HTMLParserIdioms.h"
+#include "ParsingUtilities.h"
+
+namespace WebCore {
+
+static inline bool compareByDensity(const ImageCandidate& first, const ImageCandidate& second)
+{
+ return first.density < second.density;
+}
+
+enum DescriptorTokenizerState {
+ Start,
+ InParenthesis,
+ AfterToken,
+};
+
+template<typename CharType>
+static void appendDescriptorAndReset(const CharType*& descriptorStart, const CharType* position, Vector<StringView>& descriptors)
+{
+ if (position > descriptorStart)
+ descriptors.append(StringView(descriptorStart, position - descriptorStart));
+ descriptorStart = nullptr;
+}
+
+// The following is called appendCharacter to match the spec's terminology.
+template<typename CharType>
+static void appendCharacter(const CharType* descriptorStart, const CharType* position)
+{
+ // Since we don't copy the tokens, this just set the point where the descriptor tokens start.
+ if (!descriptorStart)
+ descriptorStart = position;
+}
+
+template<typename CharType>
+static bool isEOF(const CharType* position, const CharType* end)
+{
+ return position >= end;
+}
+
+template<typename CharType>
+static void tokenizeDescriptors(const CharType*& position, const CharType* attributeEnd, Vector<StringView>& descriptors)
+{
+ DescriptorTokenizerState state = Start;
+ const CharType* descriptorsStart = position;
+ const CharType* currentDescriptorStart = descriptorsStart;
+ for (; ; ++position) {
+ switch (state) {
+ case Start:
+ if (isEOF(position, attributeEnd)) {
+ appendDescriptorAndReset(currentDescriptorStart, attributeEnd, descriptors);
+ return;
+ }
+ if (isComma(*position)) {
+ appendDescriptorAndReset(currentDescriptorStart, position, descriptors);
+ ++position;
+ return;
+ }
+ if (isHTMLSpace(*position)) {
+ appendDescriptorAndReset(currentDescriptorStart, position, descriptors);
+ currentDescriptorStart = position + 1;
+ state = AfterToken;
+ } else if (*position == '(') {
+ appendCharacter(currentDescriptorStart, position);
+ state = InParenthesis;
+ } else
+ appendCharacter(currentDescriptorStart, position);
+ break;
+ case InParenthesis:
+ if (isEOF(position, attributeEnd)) {
+ appendDescriptorAndReset(currentDescriptorStart, attributeEnd, descriptors);
+ return;
+ }
+ if (*position == ')') {
+ appendCharacter(currentDescriptorStart, position);
+ state = Start;
+ } else
+ appendCharacter(currentDescriptorStart, position);
+ break;
+ case AfterToken:
+ if (isEOF(position, attributeEnd))
+ return;
+ if (!isHTMLSpace(*position)) {
+ state = Start;
+ currentDescriptorStart = position;
+ --position;
+ }
+ break;
+ }
+ }
+}
+
+static bool parseDescriptors(Vector<StringView>& descriptors, DescriptorParsingResult& result)
+{
+ for (auto& descriptor : descriptors) {
+ if (descriptor.isEmpty())
+ continue;
+ unsigned descriptorCharPosition = descriptor.length() - 1;
+ UChar descriptorChar = descriptor[descriptorCharPosition];
+ descriptor = descriptor.substring(0, descriptorCharPosition);
+ if (descriptorChar == 'x') {
+ if (result.hasDensity() || result.hasHeight() || result.hasWidth())
+ return false;
+ std::optional<double> density = parseValidHTMLFloatingPointNumber(descriptor);
+ if (!density || density.value() < 0)
+ return false;
+ result.setDensity(density.value());
+ } else if (descriptorChar == 'w') {
+ if (result.hasDensity() || result.hasWidth())
+ return false;
+ std::optional<int> resourceWidth = parseValidHTMLNonNegativeInteger(descriptor);
+ if (!resourceWidth || resourceWidth.value() <= 0)
+ return false;
+ result.setResourceWidth(resourceWidth.value());
+ } else if (descriptorChar == 'h') {
+ // This is here only for future compat purposes.
+ // The value of the 'h' descriptor is not used.
+ if (result.hasDensity() || result.hasHeight())
+ return false;
+ std::optional<int> resourceHeight = parseValidHTMLNonNegativeInteger(descriptor);
+ if (!resourceHeight || resourceHeight.value() <= 0)
+ return false;
+ result.setResourceHeight(resourceHeight.value());
+ } else
+ return false;
+ }
+ return !result.hasHeight() || result.hasWidth();
+}
+
+// http://picture.responsiveimages.org/#parse-srcset-attr
+template<typename CharType>
+static Vector<ImageCandidate> parseImageCandidatesFromSrcsetAttribute(const CharType* attributeStart, unsigned length)
+{
+ Vector<ImageCandidate> imageCandidates;
+
+ const CharType* attributeEnd = attributeStart + length;
+
+ for (const CharType* position = attributeStart; position < attributeEnd;) {
+ // 4. Splitting loop: Collect a sequence of characters that are space characters or U+002C COMMA characters.
+ skipWhile<CharType, isHTMLSpaceOrComma<CharType> >(position, attributeEnd);
+ if (position == attributeEnd) {
+ // Contrary to spec language - descriptor parsing happens on each candidate, so when we reach the attributeEnd, we can exit.
+ break;
+ }
+ const CharType* imageURLStart = position;
+ // 6. Collect a sequence of characters that are not space characters, and let that be url.
+
+ skipUntil<CharType, isHTMLSpace<CharType> >(position, attributeEnd);
+ const CharType* imageURLEnd = position;
+
+ DescriptorParsingResult result;
+
+ // 8. If url ends with a U+002C COMMA character (,)
+ if (isComma(*(position - 1))) {
+ // Remove all trailing U+002C COMMA characters from url.
+ imageURLEnd = position - 1;
+ reverseSkipWhile<CharType, isComma>(imageURLEnd, imageURLStart);
+ ++imageURLEnd;
+ // If url is empty, then jump to the step labeled splitting loop.
+ if (imageURLStart == imageURLEnd)
+ continue;
+ } else {
+ skipWhile<CharType, isHTMLSpace<CharType>>(position, attributeEnd);
+ Vector<StringView> descriptorTokens;
+ tokenizeDescriptors(position, attributeEnd, descriptorTokens);
+ // Contrary to spec language - descriptor parsing happens on each candidate.
+ // This is a black-box equivalent, to avoid storing descriptor lists for each candidate.
+ if (!parseDescriptors(descriptorTokens, result))
+ continue;
+ }
+
+ ASSERT(imageURLEnd > imageURLStart);
+ unsigned imageURLLength = imageURLEnd - imageURLStart;
+ imageCandidates.append(ImageCandidate(StringView(imageURLStart, imageURLLength), result, ImageCandidate::SrcsetOrigin));
+ // 11. Return to the step labeled splitting loop.
+ }
+ return imageCandidates;
+}
+
+Vector<ImageCandidate> parseImageCandidatesFromSrcsetAttribute(StringView attribute)
+{
+ // FIXME: We should consider replacing the direct pointers in the parsing process with StringView and positions.
+ if (attribute.is8Bit())
+ return parseImageCandidatesFromSrcsetAttribute<LChar>(attribute.characters8(), attribute.length());
+ else
+ return parseImageCandidatesFromSrcsetAttribute<UChar>(attribute.characters16(), attribute.length());
+}
+
+static ImageCandidate pickBestImageCandidate(float deviceScaleFactor, Vector<ImageCandidate>& imageCandidates, float sourceSize)
+{
+ bool ignoreSrc = false;
+ if (imageCandidates.isEmpty())
+ return ImageCandidate();
+
+ // http://picture.responsiveimages.org/#normalize-source-densities
+ for (auto& candidate : imageCandidates) {
+ if (candidate.resourceWidth > 0) {
+ candidate.density = static_cast<float>(candidate.resourceWidth) / sourceSize;
+ ignoreSrc = true;
+ } else if (candidate.density < 0)
+ candidate.density = DefaultDensityValue;
+ }
+
+ std::stable_sort(imageCandidates.begin(), imageCandidates.end(), compareByDensity);
+
+ unsigned i;
+ for (i = 0; i < imageCandidates.size() - 1; ++i) {
+ if ((imageCandidates[i].density >= deviceScaleFactor) && (!ignoreSrc || !imageCandidates[i].srcOrigin()))
+ break;
+ }
+
+ if (imageCandidates[i].srcOrigin() && ignoreSrc) {
+ ASSERT(i > 0);
+ --i;
+ }
+ float winningDensity = imageCandidates[i].density;
+
+ unsigned winner = i;
+ // 16. If an entry b in candidates has the same associated ... pixel density as an earlier entry a in candidates,
+ // then remove entry b
+ while ((i > 0) && (imageCandidates[--i].density == winningDensity))
+ winner = i;
+
+ return imageCandidates[winner];
+}
+
+ImageCandidate bestFitSourceForImageAttributes(float deviceScaleFactor, const AtomicString& srcAttribute, const AtomicString& srcsetAttribute, float sourceSize)
+{
+ if (srcsetAttribute.isNull()) {
+ if (srcAttribute.isNull())
+ return ImageCandidate();
+ return ImageCandidate(StringView(srcAttribute), DescriptorParsingResult(), ImageCandidate::SrcOrigin);
+ }
+
+ Vector<ImageCandidate> imageCandidates = parseImageCandidatesFromSrcsetAttribute(StringView(srcsetAttribute));
+
+ if (!srcAttribute.isEmpty())
+ imageCandidates.append(ImageCandidate(StringView(srcAttribute), DescriptorParsingResult(), ImageCandidate::SrcOrigin));
+
+ return pickBestImageCandidate(deviceScaleFactor, imageCandidates, sourceSize);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLSrcsetParser.h b/Source/WebCore/html/parser/HTMLSrcsetParser.h
new file mode 100644
index 000000000..63aee53a3
--- /dev/null
+++ b/Source/WebCore/html/parser/HTMLSrcsetParser.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/text/StringView.h>
+
+namespace WebCore {
+
+const int UninitializedDescriptor = -1;
+const float DefaultDensityValue = 1.0;
+
+class DescriptorParsingResult {
+public:
+ DescriptorParsingResult()
+ : m_density(UninitializedDescriptor)
+ , m_resourceWidth(UninitializedDescriptor)
+ , m_resourceHeight(UninitializedDescriptor)
+ {
+ }
+
+ bool hasDensity() const { return m_density >= 0; }
+ bool hasWidth() const { return m_resourceWidth >= 0; }
+ bool hasHeight() const { return m_resourceHeight >= 0; }
+
+ float density() const { ASSERT(hasDensity()); return m_density; }
+ unsigned resourceWidth() const { ASSERT(hasWidth()); return m_resourceWidth; }
+ unsigned resourceHeight() const { ASSERT(hasHeight()); return m_resourceHeight; }
+
+ void setResourceWidth(int width) { ASSERT(width >= 0); m_resourceWidth = (unsigned)width; }
+ void setResourceHeight(int height) { ASSERT(height >= 0); m_resourceHeight = (unsigned)height; }
+ void setDensity(float densityToSet) { ASSERT(densityToSet >= 0); m_density = densityToSet; }
+
+private:
+ float m_density;
+ int m_resourceWidth;
+ int m_resourceHeight;
+};
+
+struct ImageCandidate {
+ enum OriginAttribute {
+ SrcsetOrigin,
+ SrcOrigin
+ };
+
+ ImageCandidate()
+ : density(DefaultDensityValue)
+ , resourceWidth(UninitializedDescriptor)
+ , originAttribute(SrcsetOrigin)
+ {
+ }
+
+ ImageCandidate(const StringView& source, const DescriptorParsingResult& result, OriginAttribute originAttribute)
+ : string(source)
+ , density(result.hasDensity() ? result.density() : UninitializedDescriptor)
+ , resourceWidth(result.hasWidth() ? result.resourceWidth() : UninitializedDescriptor)
+ , originAttribute(originAttribute)
+ {
+ }
+
+ bool srcOrigin() const
+ {
+ return (originAttribute == SrcOrigin);
+ }
+
+ bool isEmpty() const
+ {
+ return string.isEmpty();
+ }
+
+ StringView string;
+ float density;
+ int resourceWidth;
+ OriginAttribute originAttribute;
+};
+
+ImageCandidate bestFitSourceForImageAttributes(float deviceScaleFactor, const AtomicString& srcAttribute, const AtomicString& srcsetAttribute, float sourceSize);
+
+Vector<ImageCandidate> parseImageCandidatesFromSrcsetAttribute(StringView attribute);
+
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLStackItem.h b/Source/WebCore/html/parser/HTMLStackItem.h
index 953a67960..985319831 100644
--- a/Source/WebCore/html/parser/HTMLStackItem.h
+++ b/Source/WebCore/html/parser/HTMLStackItem.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012 Company 100, Inc. All rights reserved.
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,116 +24,184 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLStackItem_h
-#define HTMLStackItem_h
+#pragma once
#include "AtomicHTMLToken.h"
+#include "DocumentFragment.h"
#include "Element.h"
#include "HTMLNames.h"
#include "MathMLNames.h"
#include "SVGNames.h"
-#include <wtf/RefCounted.h>
-#include <wtf/RefPtr.h>
-#include <wtf/text/AtomicString.h>
-
namespace WebCore {
-class ContainerNode;
-
class HTMLStackItem : public RefCounted<HTMLStackItem> {
public:
- enum ItemType {
- ItemForContextElement,
- ItemForDocumentFragmentNode
- };
-
- // Used by document fragment node and context element.
- static PassRefPtr<HTMLStackItem> create(PassRefPtr<ContainerNode> node, ItemType type)
- {
- return adoptRef(new HTMLStackItem(node, type));
- }
+ // Normal HTMLElementStack and HTMLFormattingElementList items.
+ static Ref<HTMLStackItem> create(Ref<Element>&&, AtomicHTMLToken&&, const AtomicString& namespaceURI = HTMLNames::xhtmlNamespaceURI);
+ static Ref<HTMLStackItem> create(Ref<Element>&&, const AtomicString&, Vector<Attribute>&&);
- // Used by HTMLElementStack and HTMLFormattingElementList.
- static PassRefPtr<HTMLStackItem> create(PassRefPtr<ContainerNode> node, AtomicHTMLToken* token, const AtomicString& namespaceURI = HTMLNames::xhtmlNamespaceURI)
- {
- return adoptRef(new HTMLStackItem(node, token, namespaceURI));
- }
+ // Document fragment or element for parsing context.
+ static Ref<HTMLStackItem> create(Element&);
+ static Ref<HTMLStackItem> create(DocumentFragment&);
- Element* element() const { return toElement(m_node.get()); }
- ContainerNode* node() const { return m_node.get(); }
+ bool isElement() const;
+ bool isDocumentFragment() const;
- bool isDocumentFragmentNode() const { return m_isDocumentFragmentNode; }
- bool isElementNode() const { return !m_isDocumentFragmentNode; }
+ ContainerNode& node() const;
+ Element& element() const;
- const AtomicString& namespaceURI() const { return m_namespaceURI; }
- const AtomicString& localName() const { return m_tokenLocalName; }
+ const AtomicString& namespaceURI() const;
+ const AtomicString& localName() const;
- const Vector<Attribute>& attributes() const { ASSERT(m_tokenLocalName); return m_tokenAttributes; }
- Attribute* getAttributeItem(const QualifiedName& attributeName)
- {
- ASSERT(m_tokenLocalName);
- return findAttributeInVector(m_tokenAttributes, attributeName);
- }
+ const Vector<Attribute>& attributes() const;
+ const Attribute* findAttribute(const QualifiedName& attributeName) const;
- bool hasLocalName(const AtomicString& name) const { return m_tokenLocalName == name; }
- bool hasTagName(const QualifiedName& name) const { return m_tokenLocalName == name.localName() && m_namespaceURI == name.namespaceURI(); }
+ bool hasTagName(const QualifiedName&) const;
+ bool matchesHTMLTag(const AtomicString&) const;
- bool matchesHTMLTag(const AtomicString& name) const { return m_tokenLocalName == name && m_namespaceURI == HTMLNames::xhtmlNamespaceURI; }
- bool matchesHTMLTag(const QualifiedName& name) const { return m_tokenLocalName == name && m_namespaceURI == HTMLNames::xhtmlNamespaceURI; }
+private:
+ HTMLStackItem(Ref<Element>&&, AtomicHTMLToken&&, const AtomicString& namespaceURI);
+ HTMLStackItem(Ref<Element>&&, const AtomicString& localName, const AtomicString& namespaceURI, Vector<Attribute>&&);
+ explicit HTMLStackItem(Element&);
+ explicit HTMLStackItem(DocumentFragment&);
- bool causesFosterParenting()
- {
- return hasTagName(HTMLNames::tableTag)
- || hasTagName(HTMLNames::tbodyTag)
- || hasTagName(HTMLNames::tfootTag)
- || hasTagName(HTMLNames::theadTag)
- || hasTagName(HTMLNames::trTag);
- }
+ const Ref<ContainerNode> m_node;
+ const AtomicString m_namespaceURI;
+ const AtomicString m_localName;
+ const Vector<Attribute> m_attributes;
+};
- bool isInHTMLNamespace() const
- {
- // A DocumentFragment takes the place of the document element when parsing
- // fragments and should be considered in the HTML namespace.
- return namespaceURI() == HTMLNames::xhtmlNamespaceURI
- || isDocumentFragmentNode(); // FIXME: Does this also apply to ShadowRoot?
- }
+bool isInHTMLNamespace(const HTMLStackItem&);
+bool isNumberedHeaderElement(const HTMLStackItem&);
+bool isSpecialNode(const HTMLStackItem&);
- bool isNumberedHeaderElement() const
- {
- return hasTagName(HTMLNames::h1Tag)
- || hasTagName(HTMLNames::h2Tag)
- || hasTagName(HTMLNames::h3Tag)
- || hasTagName(HTMLNames::h4Tag)
- || hasTagName(HTMLNames::h5Tag)
- || hasTagName(HTMLNames::h6Tag);
- }
+inline HTMLStackItem::HTMLStackItem(Ref<Element>&& element, AtomicHTMLToken&& token, const AtomicString& namespaceURI = HTMLNames::xhtmlNamespaceURI)
+ : m_node(WTFMove(element))
+ , m_namespaceURI(namespaceURI)
+ , m_localName(token.name())
+ , m_attributes(WTFMove(token.attributes()))
+{
+}
- bool isTableBodyContextElement() const
- {
- return hasTagName(HTMLNames::tbodyTag)
- || hasTagName(HTMLNames::tfootTag)
- || hasTagName(HTMLNames::theadTag);
- }
+inline Ref<HTMLStackItem> HTMLStackItem::create(Ref<Element>&& element, AtomicHTMLToken&& token, const AtomicString& namespaceURI)
+{
+ return adoptRef(*new HTMLStackItem(WTFMove(element), WTFMove(token), namespaceURI));
+}
+
+inline HTMLStackItem::HTMLStackItem(Ref<Element>&& element, const AtomicString& localName, const AtomicString& namespaceURI, Vector<Attribute>&& attributes)
+ : m_node(WTFMove(element))
+ , m_namespaceURI(namespaceURI)
+ , m_localName(localName)
+ , m_attributes(WTFMove(attributes))
+{
+}
+
+inline Ref<HTMLStackItem> HTMLStackItem::create(Ref<Element>&& element, const AtomicString& localName, Vector<Attribute>&& attributes)
+{
+ auto& namespaceURI = element.get().namespaceURI();
+ return adoptRef(*new HTMLStackItem(WTFMove(element), localName, namespaceURI, WTFMove(attributes)));
+}
+
+inline HTMLStackItem::HTMLStackItem(Element& element)
+ : m_node(element)
+ , m_namespaceURI(element.namespaceURI())
+ , m_localName(element.localName())
+{
+}
+
+inline Ref<HTMLStackItem> HTMLStackItem::create(Element& element)
+{
+ return adoptRef(*new HTMLStackItem(element));
+}
+
+inline HTMLStackItem::HTMLStackItem(DocumentFragment& fragment)
+ : m_node(fragment)
+{
+}
+
+inline Ref<HTMLStackItem> HTMLStackItem::create(DocumentFragment& fragment)
+{
+ return adoptRef(*new HTMLStackItem(fragment));
+}
+
+inline ContainerNode& HTMLStackItem::node() const
+{
+ return m_node.get();
+}
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#special
- bool isSpecialNode() const
- {
- if (hasTagName(MathMLNames::miTag)
- || hasTagName(MathMLNames::moTag)
- || hasTagName(MathMLNames::mnTag)
- || hasTagName(MathMLNames::msTag)
- || hasTagName(MathMLNames::mtextTag)
- || hasTagName(MathMLNames::annotation_xmlTag)
- || hasTagName(SVGNames::foreignObjectTag)
- || hasTagName(SVGNames::descTag)
- || hasTagName(SVGNames::titleTag))
- return true;
- if (isDocumentFragmentNode())
- return true;
- if (!isInHTMLNamespace())
- return false;
- const AtomicString& tagName = localName();
+inline Element& HTMLStackItem::element() const
+{
+ return downcast<Element>(node());
+}
+
+inline bool HTMLStackItem::isDocumentFragment() const
+{
+ return m_localName.isNull();
+}
+
+inline bool HTMLStackItem::isElement() const
+{
+ return !isDocumentFragment();
+}
+
+inline const AtomicString& HTMLStackItem::namespaceURI() const
+{
+ return m_namespaceURI;
+}
+
+inline const AtomicString& HTMLStackItem::localName() const
+{
+ return m_localName;
+}
+
+inline const Vector<Attribute>& HTMLStackItem::attributes() const
+{
+ ASSERT(isElement());
+ return m_attributes;
+}
+
+inline const Attribute* HTMLStackItem::findAttribute(const QualifiedName& attributeName) const
+{
+ return WebCore::findAttribute(const_cast<Vector<Attribute>&>(attributes()), attributeName);
+}
+
+inline bool HTMLStackItem::hasTagName(const QualifiedName& name) const
+{
+ return m_localName == name.localName() && m_namespaceURI == name.namespaceURI();
+}
+
+inline bool HTMLStackItem::matchesHTMLTag(const AtomicString& name) const
+{
+ return m_localName == name && m_namespaceURI == HTMLNames::xhtmlNamespaceURI;
+}
+
+inline bool isInHTMLNamespace(const HTMLStackItem& item)
+{
+ // A DocumentFragment takes the place of the document element when parsing
+ // fragments and thus should be treated as if it was in the HTML namespace.
+ // FIXME: Is this also needed for a ShadowRoot that might be a non-HTML element?
+ return item.namespaceURI() == HTMLNames::xhtmlNamespaceURI || item.isDocumentFragment();
+}
+
+inline bool isNumberedHeaderElement(const HTMLStackItem& item)
+{
+ return item.namespaceURI() == HTMLNames::xhtmlNamespaceURI
+ && (item.localName() == HTMLNames::h1Tag
+ || item.localName() == HTMLNames::h2Tag
+ || item.localName() == HTMLNames::h3Tag
+ || item.localName() == HTMLNames::h4Tag
+ || item.localName() == HTMLNames::h5Tag
+ || item.localName() == HTMLNames::h6Tag);
+}
+
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#special
+inline bool isSpecialNode(const HTMLStackItem& item)
+{
+ if (item.isDocumentFragment())
+ return true;
+ const AtomicString& tagName = item.localName();
+ if (item.namespaceURI() == HTMLNames::xhtmlNamespaceURI) {
return tagName == HTMLNames::addressTag
|| tagName == HTMLNames::appletTag
|| tagName == HTMLNames::areaTag
@@ -164,7 +233,12 @@ public:
|| tagName == HTMLNames::formTag
|| tagName == HTMLNames::frameTag
|| tagName == HTMLNames::framesetTag
- || isNumberedHeaderElement()
+ || tagName == HTMLNames::h1Tag
+ || tagName == HTMLNames::h2Tag
+ || tagName == HTMLNames::h3Tag
+ || tagName == HTMLNames::h4Tag
+ || tagName == HTMLNames::h5Tag
+ || tagName == HTMLNames::h6Tag
|| tagName == HTMLNames::headTag
|| tagName == HTMLNames::headerTag
|| tagName == HTMLNames::hgroupTag
@@ -173,7 +247,6 @@ public:
|| tagName == HTMLNames::iframeTag
|| tagName == HTMLNames::imgTag
|| tagName == HTMLNames::inputTag
- || tagName == HTMLNames::isindexTag
|| tagName == HTMLNames::liTag
|| tagName == HTMLNames::linkTag
|| tagName == HTMLNames::listingTag
@@ -197,53 +270,33 @@ public:
|| tagName == HTMLNames::styleTag
|| tagName == HTMLNames::summaryTag
|| tagName == HTMLNames::tableTag
- || isTableBodyContextElement()
+ || tagName == HTMLNames::tbodyTag
|| tagName == HTMLNames::tdTag
-#if ENABLE(TEMPLATE_ELEMENT)
|| tagName == HTMLNames::templateTag
-#endif
|| tagName == HTMLNames::textareaTag
+ || tagName == HTMLNames::tfootTag
|| tagName == HTMLNames::thTag
+ || tagName == HTMLNames::theadTag
|| tagName == HTMLNames::titleTag
|| tagName == HTMLNames::trTag
|| tagName == HTMLNames::ulTag
|| tagName == HTMLNames::wbrTag
|| tagName == HTMLNames::xmpTag;
}
-
-private:
- HTMLStackItem(PassRefPtr<ContainerNode> node, ItemType type)
- : m_node(node)
- {
- switch (type) {
- case ItemForDocumentFragmentNode:
- m_isDocumentFragmentNode = true;
- break;
- case ItemForContextElement:
- m_tokenLocalName = m_node->localName();
- m_namespaceURI = m_node->namespaceURI();
- m_isDocumentFragmentNode = false;
- break;
- }
+ if (item.namespaceURI() == MathMLNames::mathmlNamespaceURI) {
+ return tagName == MathMLNames::annotation_xmlTag
+ || tagName == MathMLNames::miTag
+ || tagName == MathMLNames::moTag
+ || tagName == MathMLNames::mnTag
+ || tagName == MathMLNames::msTag
+ || tagName == MathMLNames::mtextTag;
}
-
- HTMLStackItem(PassRefPtr<ContainerNode> node, AtomicHTMLToken* token, const AtomicString& namespaceURI = HTMLNames::xhtmlNamespaceURI)
- : m_node(node)
- , m_tokenLocalName(token->name())
- , m_tokenAttributes(token->attributes())
- , m_namespaceURI(namespaceURI)
- , m_isDocumentFragmentNode(false)
- {
+ if (item.namespaceURI() == SVGNames::svgNamespaceURI) {
+ return tagName == SVGNames::descTag
+ || tagName == SVGNames::foreignObjectTag
+ || tagName == SVGNames::titleTag;
}
-
- RefPtr<ContainerNode> m_node;
-
- AtomicString m_tokenLocalName;
- Vector<Attribute> m_tokenAttributes;
- AtomicString m_namespaceURI;
- bool m_isDocumentFragmentNode;
-};
+ return false;
+}
} // namespace WebCore
-
-#endif // HTMLStackItem_h
diff --git a/Source/WebCore/html/parser/HTMLToken.h b/Source/WebCore/html/parser/HTMLToken.h
index 722ed9080..f71b21d27 100644
--- a/Source/WebCore/html/parser/HTMLToken.h
+++ b/Source/WebCore/html/parser/HTMLToken.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2013 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2015 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,47 +24,23 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLToken_h
-#define HTMLToken_h
+#pragma once
#include "Attribute.h"
-#include "HTMLToken.h"
-#include <wtf/OwnPtr.h>
-#include <wtf/PassOwnPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/RefPtr.h>
namespace WebCore {
-class DoctypeData {
- WTF_MAKE_NONCOPYABLE(DoctypeData);
+struct DoctypeData {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- DoctypeData()
- : m_hasPublicIdentifier(false)
- , m_hasSystemIdentifier(false)
- , m_forceQuirks(false)
- {
- }
-
- // FIXME: This should use String instead of Vector<UChar>.
- bool m_hasPublicIdentifier;
- bool m_hasSystemIdentifier;
- WTF::Vector<UChar> m_publicIdentifier;
- WTF::Vector<UChar> m_systemIdentifier;
- bool m_forceQuirks;
+ bool hasPublicIdentifier { false };
+ bool hasSystemIdentifier { false };
+ Vector<UChar> publicIdentifier;
+ Vector<UChar> systemIdentifier;
+ bool forceQuirks { false };
};
-static inline Attribute* findAttributeInVector(Vector<Attribute>& attributes, const QualifiedName& name)
-{
- for (unsigned i = 0; i < attributes.size(); ++i) {
- if (attributes.at(i).name().matches(name))
- return &attributes.at(i);
- }
- return 0;
-}
-
class HTMLToken {
- WTF_MAKE_NONCOPYABLE(HTMLToken);
WTF_MAKE_FAST_ALLOCATED;
public:
enum Type {
@@ -76,378 +53,402 @@ public:
EndOfFile,
};
- class Attribute {
- public:
- class Range {
- public:
- int start;
- int end;
- };
-
- Range nameRange;
- Range valueRange;
+ struct Attribute {
Vector<UChar, 32> name;
Vector<UChar, 32> value;
+
+ // Used by HTMLSourceTracker.
+ unsigned startOffset;
+ unsigned endOffset;
};
typedef Vector<Attribute, 10> AttributeList;
typedef Vector<UChar, 256> DataVector;
- HTMLToken() { clear(); }
+ HTMLToken();
- void clear()
- {
- m_type = Uninitialized;
- m_range.start = 0;
- m_range.end = 0;
- m_baseOffset = 0;
- m_data.clear();
- m_orAllData = 0;
- }
+ void clear();
- bool isUninitialized() { return m_type == Uninitialized; }
- Type type() const { return m_type; }
+ Type type() const;
- void makeEndOfFile()
- {
- ASSERT(m_type == Uninitialized);
- m_type = EndOfFile;
- }
+ // EndOfFile
- /* Range and offset methods exposed for HTMLSourceTracker and HTMLViewSourceParser */
- int startIndex() const { return m_range.start; }
- int endIndex() const { return m_range.end; }
+ void makeEndOfFile();
- void setBaseOffset(int offset)
- {
- m_baseOffset = offset;
- }
+ // StartTag, EndTag, DOCTYPE.
- void end(int endOffset)
- {
- m_range.end = endOffset - m_baseOffset;
- }
+ const DataVector& name() const;
- const DataVector& data() const
- {
- ASSERT(m_type == Character || m_type == Comment || m_type == StartTag || m_type == EndTag);
- return m_data;
- }
+ void appendToName(UChar);
- bool isAll8BitData() const
- {
- return (m_orAllData <= 0xff);
- }
+ // DOCTYPE.
- const DataVector& name() const
- {
- ASSERT(m_type == StartTag || m_type == EndTag || m_type == DOCTYPE);
- return m_data;
- }
+ void beginDOCTYPE();
+ void beginDOCTYPE(UChar);
- void appendToName(UChar character)
- {
- ASSERT(m_type == StartTag || m_type == EndTag || m_type == DOCTYPE);
- ASSERT(character);
- m_data.append(character);
- m_orAllData |= character;
- }
+ void setForceQuirks();
- /* DOCTYPE Tokens */
+ void setPublicIdentifierToEmptyString();
+ void setSystemIdentifierToEmptyString();
- bool forceQuirks() const
- {
- ASSERT(m_type == DOCTYPE);
- return m_doctypeData->m_forceQuirks;
- }
+ void appendToPublicIdentifier(UChar);
+ void appendToSystemIdentifier(UChar);
- void setForceQuirks()
- {
- ASSERT(m_type == DOCTYPE);
- m_doctypeData->m_forceQuirks = true;
- }
+ std::unique_ptr<DoctypeData> releaseDoctypeData();
- void beginDOCTYPE()
- {
- ASSERT(m_type == Uninitialized);
- m_type = DOCTYPE;
- m_doctypeData = std::make_unique<DoctypeData>();
- }
+ // StartTag, EndTag.
- void beginDOCTYPE(UChar character)
- {
- ASSERT(character);
- beginDOCTYPE();
- m_data.append(character);
- m_orAllData |= character;
- }
+ bool selfClosing() const;
+ const AttributeList& attributes() const;
- // FIXME: Distinguish between a missing public identifer and an empty one.
- const WTF::Vector<UChar>& publicIdentifier() const
- {
- ASSERT(m_type == DOCTYPE);
- return m_doctypeData->m_publicIdentifier;
- }
+ void beginStartTag(UChar);
- // FIXME: Distinguish between a missing system identifer and an empty one.
- const WTF::Vector<UChar>& systemIdentifier() const
- {
- ASSERT(m_type == DOCTYPE);
- return m_doctypeData->m_systemIdentifier;
- }
+ void beginEndTag(LChar);
+ void beginEndTag(const Vector<LChar, 32>&);
- void setPublicIdentifierToEmptyString()
- {
- ASSERT(m_type == DOCTYPE);
- m_doctypeData->m_hasPublicIdentifier = true;
- m_doctypeData->m_publicIdentifier.clear();
- }
+ void beginAttribute(unsigned offset);
+ void appendToAttributeName(UChar);
+ void appendToAttributeValue(UChar);
+ void endAttribute(unsigned offset);
- void setSystemIdentifierToEmptyString()
- {
- ASSERT(m_type == DOCTYPE);
- m_doctypeData->m_hasSystemIdentifier = true;
- m_doctypeData->m_systemIdentifier.clear();
- }
+ void setSelfClosing();
- void appendToPublicIdentifier(UChar character)
- {
- ASSERT(character);
- ASSERT(m_type == DOCTYPE);
- ASSERT(m_doctypeData->m_hasPublicIdentifier);
- m_doctypeData->m_publicIdentifier.append(character);
- }
+ // Used by HTMLTokenizer on behalf of HTMLSourceTracker.
+ void setAttributeBaseOffset(unsigned attributeBaseOffset) { m_attributeBaseOffset = attributeBaseOffset; }
- void appendToSystemIdentifier(UChar character)
- {
- ASSERT(character);
- ASSERT(m_type == DOCTYPE);
- ASSERT(m_doctypeData->m_hasSystemIdentifier);
- m_doctypeData->m_systemIdentifier.append(character);
- }
+public:
+ // Used by the XSSAuditor to nuke XSS-laden attributes.
+ void eraseValueOfAttribute(unsigned index);
+ void appendToAttributeValue(unsigned index, StringView value);
- std::unique_ptr<DoctypeData> releaseDoctypeData()
- {
- return std::move(m_doctypeData);
- }
+ // Character.
- /* Start/End Tag Tokens */
+ // Starting a character token works slightly differently than starting
+ // other types of tokens because we want to save a per-character branch.
+ // There is no beginCharacters, and appending a character sets the type.
- bool selfClosing() const
- {
- ASSERT(m_type == StartTag || m_type == EndTag);
- return m_selfClosing;
- }
+ const DataVector& characters() const;
+ bool charactersIsAll8BitData() const;
- void setSelfClosing()
- {
- ASSERT(m_type == StartTag || m_type == EndTag);
- m_selfClosing = true;
- }
+ void appendToCharacter(LChar);
+ void appendToCharacter(UChar);
+ void appendToCharacter(const Vector<LChar, 32>&);
- void beginStartTag(UChar character)
- {
- ASSERT(character);
- ASSERT(m_type == Uninitialized);
- m_type = StartTag;
- m_selfClosing = false;
- m_currentAttribute = 0;
- m_attributes.clear();
-
- m_data.append(character);
- m_orAllData |= character;
- }
+ // Comment.
- void beginEndTag(LChar character)
- {
- ASSERT(m_type == Uninitialized);
- m_type = EndTag;
- m_selfClosing = false;
- m_currentAttribute = 0;
- m_attributes.clear();
+ const DataVector& comment() const;
+ bool commentIsAll8BitData() const;
- m_data.append(character);
- }
+ void beginComment();
+ void appendToComment(UChar);
- void beginEndTag(const Vector<LChar, 32>& characters)
- {
- ASSERT(m_type == Uninitialized);
- m_type = EndTag;
- m_selfClosing = false;
- m_currentAttribute = 0;
- m_attributes.clear();
+private:
+ Type m_type;
- m_data.appendVector(characters);
- }
+ DataVector m_data;
+ UChar m_data8BitCheck;
+
+ // For StartTag and EndTag
+ bool m_selfClosing;
+ AttributeList m_attributes;
+ Attribute* m_currentAttribute;
+
+ // For DOCTYPE
+ std::unique_ptr<DoctypeData> m_doctypeData;
+
+ unsigned m_attributeBaseOffset { 0 }; // Changes across document.write() boundaries.
+};
+
+const HTMLToken::Attribute* findAttribute(const Vector<HTMLToken::Attribute>&, StringView name);
+
+inline HTMLToken::HTMLToken()
+ : m_type(Uninitialized)
+ , m_data8BitCheck(0)
+{
+}
+
+inline void HTMLToken::clear()
+{
+ m_type = Uninitialized;
+ m_data.clear();
+ m_data8BitCheck = 0;
+}
+
+inline HTMLToken::Type HTMLToken::type() const
+{
+ return m_type;
+}
+
+inline void HTMLToken::makeEndOfFile()
+{
+ ASSERT(m_type == Uninitialized);
+ m_type = EndOfFile;
+}
+
+inline const HTMLToken::DataVector& HTMLToken::name() const
+{
+ ASSERT(m_type == StartTag || m_type == EndTag || m_type == DOCTYPE);
+ return m_data;
+}
+
+inline void HTMLToken::appendToName(UChar character)
+{
+ ASSERT(m_type == StartTag || m_type == EndTag || m_type == DOCTYPE);
+ ASSERT(character);
+ m_data.append(character);
+ m_data8BitCheck |= character;
+}
+
+inline void HTMLToken::setForceQuirks()
+{
+ ASSERT(m_type == DOCTYPE);
+ m_doctypeData->forceQuirks = true;
+}
+
+inline void HTMLToken::beginDOCTYPE()
+{
+ ASSERT(m_type == Uninitialized);
+ m_type = DOCTYPE;
+ m_doctypeData = std::make_unique<DoctypeData>();
+}
+
+inline void HTMLToken::beginDOCTYPE(UChar character)
+{
+ ASSERT(character);
+ beginDOCTYPE();
+ m_data.append(character);
+ m_data8BitCheck |= character;
+}
+
+inline void HTMLToken::setPublicIdentifierToEmptyString()
+{
+ ASSERT(m_type == DOCTYPE);
+ m_doctypeData->hasPublicIdentifier = true;
+ m_doctypeData->publicIdentifier.clear();
+}
+
+inline void HTMLToken::setSystemIdentifierToEmptyString()
+{
+ ASSERT(m_type == DOCTYPE);
+ m_doctypeData->hasSystemIdentifier = true;
+ m_doctypeData->systemIdentifier.clear();
+}
+
+inline void HTMLToken::appendToPublicIdentifier(UChar character)
+{
+ ASSERT(character);
+ ASSERT(m_type == DOCTYPE);
+ ASSERT(m_doctypeData->hasPublicIdentifier);
+ m_doctypeData->publicIdentifier.append(character);
+}
+
+inline void HTMLToken::appendToSystemIdentifier(UChar character)
+{
+ ASSERT(character);
+ ASSERT(m_type == DOCTYPE);
+ ASSERT(m_doctypeData->hasSystemIdentifier);
+ m_doctypeData->systemIdentifier.append(character);
+}
+
+inline std::unique_ptr<DoctypeData> HTMLToken::releaseDoctypeData()
+{
+ return WTFMove(m_doctypeData);
+}
+
+inline bool HTMLToken::selfClosing() const
+{
+ ASSERT(m_type == StartTag || m_type == EndTag);
+ return m_selfClosing;
+}
+
+inline void HTMLToken::setSelfClosing()
+{
+ ASSERT(m_type == StartTag || m_type == EndTag);
+ m_selfClosing = true;
+}
- void addNewAttribute()
- {
- ASSERT(m_type == StartTag || m_type == EndTag);
- m_attributes.grow(m_attributes.size() + 1);
- m_currentAttribute = &m_attributes.last();
-#ifndef NDEBUG
- m_currentAttribute->nameRange.start = 0;
- m_currentAttribute->nameRange.end = 0;
- m_currentAttribute->valueRange.start = 0;
- m_currentAttribute->valueRange.end = 0;
+inline void HTMLToken::beginStartTag(UChar character)
+{
+ ASSERT(character);
+ ASSERT(m_type == Uninitialized);
+ m_type = StartTag;
+ m_selfClosing = false;
+ m_attributes.clear();
+
+#if !ASSERT_DISABLED
+ m_currentAttribute = nullptr;
#endif
- }
- void beginAttributeName(int offset)
- {
- m_currentAttribute->nameRange.start = offset - m_baseOffset;
- }
+ m_data.append(character);
+ m_data8BitCheck = character;
+}
- void endAttributeName(int offset)
- {
- int index = offset - m_baseOffset;
- m_currentAttribute->nameRange.end = index;
- m_currentAttribute->valueRange.start = index;
- m_currentAttribute->valueRange.end = index;
- }
+inline void HTMLToken::beginEndTag(LChar character)
+{
+ ASSERT(m_type == Uninitialized);
+ m_type = EndTag;
+ m_selfClosing = false;
+ m_attributes.clear();
- void beginAttributeValue(int offset)
- {
- m_currentAttribute->valueRange.start = offset - m_baseOffset;
-#ifndef NDEBUG
- m_currentAttribute->valueRange.end = 0;
+#if !ASSERT_DISABLED
+ m_currentAttribute = nullptr;
#endif
- }
- void endAttributeValue(int offset)
- {
- m_currentAttribute->valueRange.end = offset - m_baseOffset;
- }
+ m_data.append(character);
+}
- void appendToAttributeName(UChar character)
- {
- ASSERT(character);
- ASSERT(m_type == StartTag || m_type == EndTag);
- // FIXME: We should be able to add the following ASSERT once we fix
- // https://bugs.webkit.org/show_bug.cgi?id=62971
- // ASSERT(m_currentAttribute->nameRange.start);
- m_currentAttribute->name.append(character);
- }
+inline void HTMLToken::beginEndTag(const Vector<LChar, 32>& characters)
+{
+ ASSERT(m_type == Uninitialized);
+ m_type = EndTag;
+ m_selfClosing = false;
+ m_attributes.clear();
- void appendToAttributeValue(UChar character)
- {
- ASSERT(character);
- ASSERT(m_type == StartTag || m_type == EndTag);
- ASSERT(m_currentAttribute->valueRange.start);
- m_currentAttribute->value.append(character);
- }
+#if !ASSERT_DISABLED
+ m_currentAttribute = nullptr;
+#endif
- void appendToAttributeValue(size_t i, const String& value)
- {
- ASSERT(!value.isEmpty());
- ASSERT(m_type == StartTag || m_type == EndTag);
- append(m_attributes[i].value, value);
- }
+ m_data.appendVector(characters);
+}
- const AttributeList& attributes() const
- {
- ASSERT(m_type == StartTag || m_type == EndTag);
- return m_attributes;
- }
+inline void HTMLToken::beginAttribute(unsigned offset)
+{
+ ASSERT(m_type == StartTag || m_type == EndTag);
+ ASSERT(offset);
- const Attribute* getAttributeItem(const QualifiedName& name) const
- {
- for (unsigned i = 0; i < m_attributes.size(); ++i) {
- if (AtomicString(m_attributes.at(i).name) == name.localName())
- return &m_attributes.at(i);
- }
- return 0;
- }
+ m_attributes.grow(m_attributes.size() + 1);
+ m_currentAttribute = &m_attributes.last();
- // Used by the XSSAuditor to nuke XSS-laden attributes.
- void eraseValueOfAttribute(size_t i)
- {
- ASSERT(m_type == StartTag || m_type == EndTag);
- m_attributes[i].value.clear();
- }
+ m_currentAttribute->startOffset = offset - m_attributeBaseOffset;
+}
- /* Character Tokens */
+inline void HTMLToken::endAttribute(unsigned offset)
+{
+ ASSERT(offset);
+ ASSERT(m_currentAttribute);
+ m_currentAttribute->endOffset = offset - m_attributeBaseOffset;
+#if !ASSERT_DISABLED
+ m_currentAttribute = nullptr;
+#endif
+}
- // Starting a character token works slightly differently than starting
- // other types of tokens because we want to save a per-character branch.
- void ensureIsCharacterToken()
- {
- ASSERT(m_type == Uninitialized || m_type == Character);
- m_type = Character;
- }
+inline void HTMLToken::appendToAttributeName(UChar character)
+{
+ ASSERT(character);
+ ASSERT(m_type == StartTag || m_type == EndTag);
+ ASSERT(m_currentAttribute);
+ m_currentAttribute->name.append(character);
+}
- const DataVector& characters() const
- {
- ASSERT(m_type == Character);
- return m_data;
- }
+inline void HTMLToken::appendToAttributeValue(UChar character)
+{
+ ASSERT(character);
+ ASSERT(m_type == StartTag || m_type == EndTag);
+ ASSERT(m_currentAttribute);
+ m_currentAttribute->value.append(character);
+}
- void appendToCharacter(char character)
- {
- ASSERT(m_type == Character);
- m_data.append(character);
- }
+inline void HTMLToken::appendToAttributeValue(unsigned i, StringView value)
+{
+ ASSERT(!value.isEmpty());
+ ASSERT(m_type == StartTag || m_type == EndTag);
+ append(m_attributes[i].value, value);
+}
- void appendToCharacter(UChar character)
- {
- ASSERT(m_type == Character);
- m_data.append(character);
- m_orAllData |= character;
- }
+inline const HTMLToken::AttributeList& HTMLToken::attributes() const
+{
+ ASSERT(m_type == StartTag || m_type == EndTag);
+ return m_attributes;
+}
- void appendToCharacter(const Vector<LChar, 32>& characters)
- {
- ASSERT(m_type == Character);
- m_data.appendVector(characters);
- }
+// Used by the XSSAuditor to nuke XSS-laden attributes.
+inline void HTMLToken::eraseValueOfAttribute(unsigned i)
+{
+ ASSERT(m_type == StartTag || m_type == EndTag);
+ ASSERT(i < m_attributes.size());
+ m_attributes[i].value.clear();
+}
- /* Comment Tokens */
+inline const HTMLToken::DataVector& HTMLToken::characters() const
+{
+ ASSERT(m_type == Character);
+ return m_data;
+}
- const DataVector& comment() const
- {
- ASSERT(m_type == Comment);
- return m_data;
- }
+inline bool HTMLToken::charactersIsAll8BitData() const
+{
+ ASSERT(m_type == Character);
+ return m_data8BitCheck <= 0xFF;
+}
- void beginComment()
- {
- ASSERT(m_type == Uninitialized);
- m_type = Comment;
- }
+inline void HTMLToken::appendToCharacter(LChar character)
+{
+ ASSERT(m_type == Uninitialized || m_type == Character);
+ m_type = Character;
+ m_data.append(character);
+}
- void appendToComment(UChar character)
- {
- ASSERT(character);
- ASSERT(m_type == Comment);
- m_data.append(character);
- m_orAllData |= character;
- }
+inline void HTMLToken::appendToCharacter(UChar character)
+{
+ ASSERT(m_type == Uninitialized || m_type == Character);
+ m_type = Character;
+ m_data.append(character);
+ m_data8BitCheck |= character;
+}
- void eraseCharacters()
- {
- ASSERT(m_type == Character);
- m_data.clear();
- m_orAllData = 0;
- }
+inline void HTMLToken::appendToCharacter(const Vector<LChar, 32>& characters)
+{
+ ASSERT(m_type == Uninitialized || m_type == Character);
+ m_type = Character;
+ m_data.appendVector(characters);
+}
-private:
- Type m_type;
- Attribute::Range m_range; // Always starts at zero.
- int m_baseOffset;
- DataVector m_data;
- UChar m_orAllData;
+inline const HTMLToken::DataVector& HTMLToken::comment() const
+{
+ ASSERT(m_type == Comment);
+ return m_data;
+}
- // For StartTag and EndTag
- bool m_selfClosing;
- AttributeList m_attributes;
+inline bool HTMLToken::commentIsAll8BitData() const
+{
+ ASSERT(m_type == Comment);
+ return m_data8BitCheck <= 0xFF;
+}
- // A pointer into m_attributes used during lexing.
- Attribute* m_currentAttribute;
+inline void HTMLToken::beginComment()
+{
+ ASSERT(m_type == Uninitialized);
+ m_type = Comment;
+}
- // For DOCTYPE
- std::unique_ptr<DoctypeData> m_doctypeData;
-};
+inline void HTMLToken::appendToComment(UChar character)
+{
+ ASSERT(character);
+ ASSERT(m_type == Comment);
+ m_data.append(character);
+ m_data8BitCheck |= character;
+}
+inline bool nameMatches(const HTMLToken::Attribute& attribute, StringView name)
+{
+ unsigned size = name.length();
+ if (attribute.name.size() != size)
+ return false;
+ for (unsigned i = 0; i < size; ++i) {
+ // FIXME: The one caller that uses this probably wants to ignore letter case.
+ if (attribute.name[i] != name[i])
+ return false;
+ }
+ return true;
}
-#endif
+inline const HTMLToken::Attribute* findAttribute(const HTMLToken::AttributeList& attributes, StringView name)
+{
+ for (auto& attribute : attributes) {
+ if (nameMatches(attribute, name))
+ return &attribute;
+ }
+ return nullptr;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLTokenizer.cpp b/Source/WebCore/html/parser/HTMLTokenizer.cpp
index 2abefaf68..985c618dd 100644
--- a/Source/WebCore/html/parser/HTMLTokenizer.cpp
+++ b/Source/WebCore/html/parser/HTMLTokenizer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008-2016 Apple Inc. All Rights Reserved.
* Copyright (C) 2009 Torch Mobile, Inc. http://www.torchmobile.com/
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
*
@@ -29,13 +29,9 @@
#include "HTMLTokenizer.h"
#include "HTMLEntityParser.h"
-#include "HTMLTreeBuilder.h"
+#include "HTMLNames.h"
#include "MarkupTokenizerInlines.h"
-#include "NotImplemented.h"
-#include <wtf/ASCIICType.h>
-#include <wtf/CurrentTime.h>
-#include <wtf/text/CString.h>
-#include <wtf/unicode/Unicode.h>
+#include <wtf/text/StringBuilder.h>
using namespace WTF;
@@ -43,81 +39,95 @@ namespace WebCore {
using namespace HTMLNames;
-// This has to go in a .cpp file, as the linker doesn't like it being included more than once.
-// We don't have an HTMLToken.cpp though, so this is the next best place.
-QualifiedName AtomicHTMLToken::nameForAttribute(const HTMLToken::Attribute& attribute) const
+static inline LChar convertASCIIAlphaToLower(UChar character)
{
- return QualifiedName(nullAtom, AtomicString(attribute.name), nullAtom);
+ ASSERT(isASCIIAlpha(character));
+ return toASCIILowerUnchecked(character);
}
-bool AtomicHTMLToken::usesName() const
+static inline bool vectorEqualsString(const Vector<LChar, 32>& vector, const char* string)
{
- return m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag || m_type == HTMLToken::DOCTYPE;
+ unsigned size = vector.size();
+ for (unsigned i = 0; i < size; ++i) {
+ if (!string[i] || vector[i] != string[i])
+ return false;
+ }
+ return !string[size];
}
-bool AtomicHTMLToken::usesAttributes() const
+inline bool HTMLTokenizer::inEndTagBufferingState() const
{
- return m_type == HTMLToken::StartTag || m_type == HTMLToken::EndTag;
+ switch (m_state) {
+ case RCDATAEndTagOpenState:
+ case RCDATAEndTagNameState:
+ case RAWTEXTEndTagOpenState:
+ case RAWTEXTEndTagNameState:
+ case ScriptDataEndTagOpenState:
+ case ScriptDataEndTagNameState:
+ case ScriptDataEscapedEndTagOpenState:
+ case ScriptDataEscapedEndTagNameState:
+ return true;
+ default:
+ return false;
+ }
}
-static inline UChar toLowerCase(UChar cc)
+HTMLTokenizer::HTMLTokenizer(const HTMLParserOptions& options)
+ : m_preprocessor(*this)
+ , m_options(options)
{
- ASSERT(isASCIIUpper(cc));
- const int lowerCaseOffset = 0x20;
- return cc + lowerCaseOffset;
}
-static inline bool vectorEqualsString(const Vector<LChar, 32>& vector, const String& string)
+inline void HTMLTokenizer::bufferASCIICharacter(UChar character)
{
- if (vector.size() != string.length())
- return false;
-
- if (!string.length())
- return true;
+ ASSERT(character != kEndOfFileMarker);
+ ASSERT(isASCII(character));
+ LChar narrowedCharacter = character;
+ m_token.appendToCharacter(narrowedCharacter);
+}
- return equal(string.impl(), vector.data(), vector.size());
+inline void HTMLTokenizer::bufferCharacter(UChar character)
+{
+ ASSERT(character != kEndOfFileMarker);
+ m_token.appendToCharacter(character);
}
-static inline bool isEndTagBufferingState(HTMLTokenizer::State state)
+inline bool HTMLTokenizer::emitAndResumeInDataState(SegmentedString& source)
{
- switch (state) {
- case HTMLTokenizer::RCDATAEndTagOpenState:
- case HTMLTokenizer::RCDATAEndTagNameState:
- case HTMLTokenizer::RAWTEXTEndTagOpenState:
- case HTMLTokenizer::RAWTEXTEndTagNameState:
- case HTMLTokenizer::ScriptDataEndTagOpenState:
- case HTMLTokenizer::ScriptDataEndTagNameState:
- case HTMLTokenizer::ScriptDataEscapedEndTagOpenState:
- case HTMLTokenizer::ScriptDataEscapedEndTagNameState:
- return true;
- default:
- return false;
- }
+ saveEndTagNameIfNeeded();
+ m_state = DataState;
+ source.advancePastNonNewline();
+ return true;
}
-#define HTML_BEGIN_STATE(stateName) BEGIN_STATE(HTMLTokenizer, stateName)
-#define HTML_RECONSUME_IN(stateName) RECONSUME_IN(HTMLTokenizer, stateName)
-#define HTML_ADVANCE_TO(stateName) ADVANCE_TO(HTMLTokenizer, stateName)
-#define HTML_SWITCH_TO(stateName) SWITCH_TO(HTMLTokenizer, stateName)
+inline bool HTMLTokenizer::emitAndReconsumeInDataState()
+{
+ saveEndTagNameIfNeeded();
+ m_state = DataState;
+ return true;
+}
-HTMLTokenizer::HTMLTokenizer(const HTMLParserOptions& options)
- : m_inputStreamPreprocessor(this)
- , m_options(options)
+inline bool HTMLTokenizer::emitEndOfFile(SegmentedString& source)
{
- reset();
+ m_state = DataState;
+ if (haveBufferedCharacterToken())
+ return true;
+ source.advance();
+ m_token.clear();
+ m_token.makeEndOfFile();
+ return true;
}
-HTMLTokenizer::~HTMLTokenizer()
+inline void HTMLTokenizer::saveEndTagNameIfNeeded()
{
+ ASSERT(m_token.type() != HTMLToken::Uninitialized);
+ if (m_token.type() == HTMLToken::StartTag)
+ m_appropriateEndTagName = m_token.name();
}
-void HTMLTokenizer::reset()
+inline bool HTMLTokenizer::haveBufferedCharacterToken() const
{
- m_state = HTMLTokenizer::DataState;
- m_token = 0;
- m_forceNullCharacterReplacement = false;
- m_shouldAllowCDATA = false;
- m_additionalAllowedCharacter = '\0';
+ return m_token.type() == HTMLToken::Character;
}
inline bool HTMLTokenizer::processEntity(SegmentedString& source)
@@ -129,7 +139,7 @@ inline bool HTMLTokenizer::processEntity(SegmentedString& source)
return false;
if (!success) {
ASSERT(decodedEntity.isEmpty());
- bufferCharacter('&');
+ bufferASCIICharacter('&');
} else {
for (unsigned i = 0; i < decodedEntity.length(); ++i)
bufferCharacter(decodedEntity[i]);
@@ -137,1426 +147,1246 @@ inline bool HTMLTokenizer::processEntity(SegmentedString& source)
return true;
}
-bool HTMLTokenizer::flushBufferedEndTag(SegmentedString& source)
+void HTMLTokenizer::flushBufferedEndTag()
{
- ASSERT(m_token->type() == HTMLToken::Character || m_token->type() == HTMLToken::Uninitialized);
- source.advanceAndUpdateLineNumber();
- if (m_token->type() == HTMLToken::Character)
- return true;
- m_token->beginEndTag(m_bufferedEndTagName);
+ m_token.beginEndTag(m_bufferedEndTagName);
m_bufferedEndTagName.clear();
m_appropriateEndTagName.clear();
m_temporaryBuffer.clear();
+}
+
+bool HTMLTokenizer::commitToPartialEndTag(SegmentedString& source, UChar character, State state)
+{
+ ASSERT(source.currentCharacter() == character);
+ appendToTemporaryBuffer(character);
+ source.advancePastNonNewline();
+
+ if (haveBufferedCharacterToken()) {
+ // Emit the buffered character token.
+ // The next call to processToken will flush the buffered end tag and continue parsing it.
+ m_state = state;
+ return true;
+ }
+
+ flushBufferedEndTag();
return false;
}
-#define FLUSH_AND_ADVANCE_TO(stateName) \
- do { \
- m_state = HTMLTokenizer::stateName; \
- if (flushBufferedEndTag(source)) \
- return true; \
- if (source.isEmpty() \
- || !m_inputStreamPreprocessor.peek(source)) \
- return haveBufferedCharacterToken(); \
- cc = m_inputStreamPreprocessor.nextInputCharacter(); \
- goto stateName; \
- } while (false)
-
-bool HTMLTokenizer::flushEmitAndResumeIn(SegmentedString& source, HTMLTokenizer::State state)
+bool HTMLTokenizer::commitToCompleteEndTag(SegmentedString& source)
{
- m_state = state;
- flushBufferedEndTag(source);
+ ASSERT(source.currentCharacter() == '>');
+ appendToTemporaryBuffer('>');
+ source.advancePastNonNewline();
+
+ m_state = DataState;
+
+ if (haveBufferedCharacterToken()) {
+ // Emit the character token we already have.
+ // The next call to processToken will flush the buffered end tag and emit it.
+ return true;
+ }
+
+ flushBufferedEndTag();
return true;
}
-bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
+bool HTMLTokenizer::processToken(SegmentedString& source)
{
- // If we have a token in progress, then we're supposed to be called back
- // with the same token so we can finish it.
- ASSERT(!m_token || m_token == &token || token.type() == HTMLToken::Uninitialized);
- m_token = &token;
-
- if (!m_bufferedEndTagName.isEmpty() && !isEndTagBufferingState(m_state)) {
- // FIXME: This should call flushBufferedEndTag().
- // We started an end tag during our last iteration.
- m_token->beginEndTag(m_bufferedEndTagName);
- m_bufferedEndTagName.clear();
- m_appropriateEndTagName.clear();
- m_temporaryBuffer.clear();
- if (m_state == HTMLTokenizer::DataState) {
- // We're back in the data state, so we must be done with the tag.
+ if (!m_bufferedEndTagName.isEmpty() && !inEndTagBufferingState()) {
+ // We are back here after emitting a character token that came just before an end tag.
+ // To continue parsing the end tag we need to move the buffered tag name into the token.
+ flushBufferedEndTag();
+
+ // If we are in the data state, the end tag is already complete and we should emit it
+ // now, otherwise, we want to resume parsing the partial end tag.
+ if (m_state == DataState)
return true;
- }
}
- if (source.isEmpty() || !m_inputStreamPreprocessor.peek(source))
+ if (!m_preprocessor.peek(source, isNullCharacterSkippingState(m_state)))
return haveBufferedCharacterToken();
- UChar cc = m_inputStreamPreprocessor.nextInputCharacter();
+ UChar character = m_preprocessor.nextInputCharacter();
- // Source: http://www.whatwg.org/specs/web-apps/current-work/#tokenisation0
+ // https://html.spec.whatwg.org/#tokenization
switch (m_state) {
- HTML_BEGIN_STATE(DataState) {
- if (cc == '&')
- HTML_ADVANCE_TO(CharacterReferenceInDataState);
- else if (cc == '<') {
- if (m_token->type() == HTMLToken::Character) {
- // We have a bunch of character tokens queued up that we
- // are emitting lazily here.
- return true;
- }
- HTML_ADVANCE_TO(TagOpenState);
- } else if (cc == kEndOfFileMarker)
- return emitEndOfFile(source);
- else {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(DataState);
- }
- }
- END_STATE()
-
- HTML_BEGIN_STATE(CharacterReferenceInDataState) {
- if (!processEntity(source))
- return haveBufferedCharacterToken();
- HTML_SWITCH_TO(DataState);
- }
- END_STATE()
- HTML_BEGIN_STATE(RCDATAState) {
- if (cc == '&')
- HTML_ADVANCE_TO(CharacterReferenceInRCDATAState);
- else if (cc == '<')
- HTML_ADVANCE_TO(RCDATALessThanSignState);
- else if (cc == kEndOfFileMarker)
- return emitEndOfFile(source);
- else {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(RCDATAState);
+ BEGIN_STATE(DataState)
+ if (character == '&')
+ ADVANCE_PAST_NON_NEWLINE_TO(CharacterReferenceInDataState);
+ if (character == '<') {
+ if (haveBufferedCharacterToken())
+ RETURN_IN_CURRENT_STATE(true);
+ ADVANCE_PAST_NON_NEWLINE_TO(TagOpenState);
}
- }
+ if (character == kEndOfFileMarker)
+ return emitEndOfFile(source);
+ bufferCharacter(character);
+ ADVANCE_TO(DataState);
END_STATE()
- HTML_BEGIN_STATE(CharacterReferenceInRCDATAState) {
+ BEGIN_STATE(CharacterReferenceInDataState)
if (!processEntity(source))
- return haveBufferedCharacterToken();
- HTML_SWITCH_TO(RCDATAState);
- }
+ RETURN_IN_CURRENT_STATE(haveBufferedCharacterToken());
+ SWITCH_TO(DataState);
END_STATE()
- HTML_BEGIN_STATE(RAWTEXTState) {
- if (cc == '<')
- HTML_ADVANCE_TO(RAWTEXTLessThanSignState);
- else if (cc == kEndOfFileMarker)
- return emitEndOfFile(source);
- else {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(RAWTEXTState);
- }
- }
+ BEGIN_STATE(RCDATAState)
+ if (character == '&')
+ ADVANCE_PAST_NON_NEWLINE_TO(CharacterReferenceInRCDATAState);
+ if (character == '<')
+ ADVANCE_PAST_NON_NEWLINE_TO(RCDATALessThanSignState);
+ if (character == kEndOfFileMarker)
+ RECONSUME_IN(DataState);
+ bufferCharacter(character);
+ ADVANCE_TO(RCDATAState);
END_STATE()
- HTML_BEGIN_STATE(ScriptDataState) {
- if (cc == '<')
- HTML_ADVANCE_TO(ScriptDataLessThanSignState);
- else if (cc == kEndOfFileMarker)
- return emitEndOfFile(source);
- else {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataState);
+ BEGIN_STATE(CharacterReferenceInRCDATAState)
+ if (!processEntity(source))
+ RETURN_IN_CURRENT_STATE(haveBufferedCharacterToken());
+ SWITCH_TO(RCDATAState);
+ END_STATE()
+
+ BEGIN_STATE(RAWTEXTState)
+ if (character == '<')
+ ADVANCE_PAST_NON_NEWLINE_TO(RAWTEXTLessThanSignState);
+ if (character == kEndOfFileMarker)
+ RECONSUME_IN(DataState);
+ bufferCharacter(character);
+ ADVANCE_TO(RAWTEXTState);
+ END_STATE()
+
+ BEGIN_STATE(ScriptDataState)
+ if (character == '<')
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataLessThanSignState);
+ if (character == kEndOfFileMarker)
+ RECONSUME_IN(DataState);
+ bufferCharacter(character);
+ ADVANCE_TO(ScriptDataState);
+ END_STATE()
+
+ BEGIN_STATE(PLAINTEXTState)
+ if (character == kEndOfFileMarker)
+ RECONSUME_IN(DataState);
+ bufferCharacter(character);
+ ADVANCE_TO(PLAINTEXTState);
+ END_STATE()
+
+ BEGIN_STATE(TagOpenState)
+ if (character == '!')
+ ADVANCE_PAST_NON_NEWLINE_TO(MarkupDeclarationOpenState);
+ if (character == '/')
+ ADVANCE_PAST_NON_NEWLINE_TO(EndTagOpenState);
+ if (isASCIIAlpha(character)) {
+ m_token.beginStartTag(convertASCIIAlphaToLower(character));
+ ADVANCE_PAST_NON_NEWLINE_TO(TagNameState);
}
- }
- END_STATE()
-
- HTML_BEGIN_STATE(PLAINTEXTState) {
- if (cc == kEndOfFileMarker)
- return emitEndOfFile(source);
- bufferCharacter(cc);
- HTML_ADVANCE_TO(PLAINTEXTState);
- }
- END_STATE()
-
- HTML_BEGIN_STATE(TagOpenState) {
- if (cc == '!')
- HTML_ADVANCE_TO(MarkupDeclarationOpenState);
- else if (cc == '/')
- HTML_ADVANCE_TO(EndTagOpenState);
- else if (isASCIIUpper(cc)) {
- m_token->beginStartTag(toLowerCase(cc));
- HTML_ADVANCE_TO(TagNameState);
- } else if (isASCIILower(cc)) {
- m_token->beginStartTag(cc);
- HTML_ADVANCE_TO(TagNameState);
- } else if (cc == '?') {
+ if (character == '?') {
parseError();
// The spec consumes the current character before switching
// to the bogus comment state, but it's easier to implement
// if we reconsume the current character.
- HTML_RECONSUME_IN(BogusCommentState);
- } else {
- parseError();
- bufferCharacter('<');
- HTML_RECONSUME_IN(DataState);
+ RECONSUME_IN(BogusCommentState);
}
- }
+ parseError();
+ bufferASCIICharacter('<');
+ RECONSUME_IN(DataState);
END_STATE()
- HTML_BEGIN_STATE(EndTagOpenState) {
- if (isASCIIUpper(cc)) {
- m_token->beginEndTag(static_cast<LChar>(toLowerCase(cc)));
+ BEGIN_STATE(EndTagOpenState)
+ if (isASCIIAlpha(character)) {
+ m_token.beginEndTag(convertASCIIAlphaToLower(character));
m_appropriateEndTagName.clear();
- HTML_ADVANCE_TO(TagNameState);
- } else if (isASCIILower(cc)) {
- m_token->beginEndTag(static_cast<LChar>(cc));
- m_appropriateEndTagName.clear();
- HTML_ADVANCE_TO(TagNameState);
- } else if (cc == '>') {
- parseError();
- HTML_ADVANCE_TO(DataState);
- } else if (cc == kEndOfFileMarker) {
+ ADVANCE_PAST_NON_NEWLINE_TO(TagNameState);
+ }
+ if (character == '>') {
parseError();
- bufferCharacter('<');
- bufferCharacter('/');
- HTML_RECONSUME_IN(DataState);
- } else {
+ ADVANCE_PAST_NON_NEWLINE_TO(DataState);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- HTML_RECONSUME_IN(BogusCommentState);
+ bufferASCIICharacter('<');
+ bufferASCIICharacter('/');
+ RECONSUME_IN(DataState);
}
- }
+ parseError();
+ RECONSUME_IN(BogusCommentState);
END_STATE()
- HTML_BEGIN_STATE(TagNameState) {
- if (isTokenizerWhitespace(cc))
- HTML_ADVANCE_TO(BeforeAttributeNameState);
- else if (cc == '/')
- HTML_ADVANCE_TO(SelfClosingStartTagState);
- else if (cc == '>')
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- else if (m_options.usePreHTML5ParserQuirks && cc == '<')
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- else if (isASCIIUpper(cc)) {
- m_token->appendToName(toLowerCase(cc));
- HTML_ADVANCE_TO(TagNameState);
- } else if (cc == kEndOfFileMarker) {
- parseError();
- HTML_RECONSUME_IN(DataState);
- } else {
- m_token->appendToName(cc);
- HTML_ADVANCE_TO(TagNameState);
+ BEGIN_STATE(TagNameState)
+ if (isTokenizerWhitespace(character))
+ ADVANCE_TO(BeforeAttributeNameState);
+ if (character == '/')
+ ADVANCE_PAST_NON_NEWLINE_TO(SelfClosingStartTagState);
+ if (character == '>')
+ return emitAndResumeInDataState(source);
+ if (m_options.usePreHTML5ParserQuirks && character == '<')
+ return emitAndReconsumeInDataState();
+ if (character == kEndOfFileMarker) {
+ parseError();
+ RECONSUME_IN(DataState);
}
- }
+ m_token.appendToName(toASCIILower(character));
+ ADVANCE_PAST_NON_NEWLINE_TO(TagNameState);
END_STATE()
- HTML_BEGIN_STATE(RCDATALessThanSignState) {
- if (cc == '/') {
+ BEGIN_STATE(RCDATALessThanSignState)
+ if (character == '/') {
m_temporaryBuffer.clear();
ASSERT(m_bufferedEndTagName.isEmpty());
- HTML_ADVANCE_TO(RCDATAEndTagOpenState);
- } else {
- bufferCharacter('<');
- HTML_RECONSUME_IN(RCDATAState);
+ ADVANCE_PAST_NON_NEWLINE_TO(RCDATAEndTagOpenState);
}
- }
+ bufferASCIICharacter('<');
+ RECONSUME_IN(RCDATAState);
END_STATE()
- HTML_BEGIN_STATE(RCDATAEndTagOpenState) {
- if (isASCIIUpper(cc)) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
- HTML_ADVANCE_TO(RCDATAEndTagNameState);
- } else if (isASCIILower(cc)) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- addToPossibleEndTag(static_cast<LChar>(cc));
- HTML_ADVANCE_TO(RCDATAEndTagNameState);
- } else {
- bufferCharacter('<');
- bufferCharacter('/');
- HTML_RECONSUME_IN(RCDATAState);
+ BEGIN_STATE(RCDATAEndTagOpenState)
+ if (isASCIIAlpha(character)) {
+ appendToTemporaryBuffer(character);
+ appendToPossibleEndTag(convertASCIIAlphaToLower(character));
+ ADVANCE_PAST_NON_NEWLINE_TO(RCDATAEndTagNameState);
}
- }
+ bufferASCIICharacter('<');
+ bufferASCIICharacter('/');
+ RECONSUME_IN(RCDATAState);
END_STATE()
- HTML_BEGIN_STATE(RCDATAEndTagNameState) {
- if (isASCIIUpper(cc)) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
- HTML_ADVANCE_TO(RCDATAEndTagNameState);
- } else if (isASCIILower(cc)) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- addToPossibleEndTag(static_cast<LChar>(cc));
- HTML_ADVANCE_TO(RCDATAEndTagNameState);
- } else {
- if (isTokenizerWhitespace(cc)) {
- if (isAppropriateEndTag()) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- FLUSH_AND_ADVANCE_TO(BeforeAttributeNameState);
- }
- } else if (cc == '/') {
- if (isAppropriateEndTag()) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- FLUSH_AND_ADVANCE_TO(SelfClosingStartTagState);
- }
- } else if (cc == '>') {
- if (isAppropriateEndTag()) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- return flushEmitAndResumeIn(source, HTMLTokenizer::DataState);
- }
+ BEGIN_STATE(RCDATAEndTagNameState)
+ if (isASCIIAlpha(character)) {
+ appendToTemporaryBuffer(character);
+ appendToPossibleEndTag(convertASCIIAlphaToLower(character));
+ ADVANCE_PAST_NON_NEWLINE_TO(RCDATAEndTagNameState);
+ }
+ if (isTokenizerWhitespace(character)) {
+ if (isAppropriateEndTag()) {
+ if (commitToPartialEndTag(source, character, BeforeAttributeNameState))
+ return true;
+ SWITCH_TO(BeforeAttributeNameState);
}
- bufferCharacter('<');
- bufferCharacter('/');
- m_token->appendToCharacter(m_temporaryBuffer);
- m_bufferedEndTagName.clear();
- m_temporaryBuffer.clear();
- HTML_RECONSUME_IN(RCDATAState);
+ } else if (character == '/') {
+ if (isAppropriateEndTag()) {
+ if (commitToPartialEndTag(source, '/', SelfClosingStartTagState))
+ return true;
+ SWITCH_TO(SelfClosingStartTagState);
+ }
+ } else if (character == '>') {
+ if (isAppropriateEndTag())
+ return commitToCompleteEndTag(source);
}
- }
+ bufferASCIICharacter('<');
+ bufferASCIICharacter('/');
+ m_token.appendToCharacter(m_temporaryBuffer);
+ m_bufferedEndTagName.clear();
+ m_temporaryBuffer.clear();
+ RECONSUME_IN(RCDATAState);
END_STATE()
- HTML_BEGIN_STATE(RAWTEXTLessThanSignState) {
- if (cc == '/') {
+ BEGIN_STATE(RAWTEXTLessThanSignState)
+ if (character == '/') {
m_temporaryBuffer.clear();
ASSERT(m_bufferedEndTagName.isEmpty());
- HTML_ADVANCE_TO(RAWTEXTEndTagOpenState);
- } else {
- bufferCharacter('<');
- HTML_RECONSUME_IN(RAWTEXTState);
+ ADVANCE_PAST_NON_NEWLINE_TO(RAWTEXTEndTagOpenState);
}
- }
+ bufferASCIICharacter('<');
+ RECONSUME_IN(RAWTEXTState);
END_STATE()
- HTML_BEGIN_STATE(RAWTEXTEndTagOpenState) {
- if (isASCIIUpper(cc)) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
- HTML_ADVANCE_TO(RAWTEXTEndTagNameState);
- } else if (isASCIILower(cc)) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- addToPossibleEndTag(static_cast<LChar>(cc));
- HTML_ADVANCE_TO(RAWTEXTEndTagNameState);
- } else {
- bufferCharacter('<');
- bufferCharacter('/');
- HTML_RECONSUME_IN(RAWTEXTState);
+ BEGIN_STATE(RAWTEXTEndTagOpenState)
+ if (isASCIIAlpha(character)) {
+ appendToTemporaryBuffer(character);
+ appendToPossibleEndTag(convertASCIIAlphaToLower(character));
+ ADVANCE_PAST_NON_NEWLINE_TO(RAWTEXTEndTagNameState);
}
- }
+ bufferASCIICharacter('<');
+ bufferASCIICharacter('/');
+ RECONSUME_IN(RAWTEXTState);
END_STATE()
- HTML_BEGIN_STATE(RAWTEXTEndTagNameState) {
- if (isASCIIUpper(cc)) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
- HTML_ADVANCE_TO(RAWTEXTEndTagNameState);
- } else if (isASCIILower(cc)) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- addToPossibleEndTag(static_cast<LChar>(cc));
- HTML_ADVANCE_TO(RAWTEXTEndTagNameState);
- } else {
- if (isTokenizerWhitespace(cc)) {
- if (isAppropriateEndTag()) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- FLUSH_AND_ADVANCE_TO(BeforeAttributeNameState);
- }
- } else if (cc == '/') {
- if (isAppropriateEndTag()) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- FLUSH_AND_ADVANCE_TO(SelfClosingStartTagState);
- }
- } else if (cc == '>') {
- if (isAppropriateEndTag()) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- return flushEmitAndResumeIn(source, HTMLTokenizer::DataState);
- }
+ BEGIN_STATE(RAWTEXTEndTagNameState)
+ if (isASCIIAlpha(character)) {
+ appendToTemporaryBuffer(character);
+ appendToPossibleEndTag(convertASCIIAlphaToLower(character));
+ ADVANCE_PAST_NON_NEWLINE_TO(RAWTEXTEndTagNameState);
+ }
+ if (isTokenizerWhitespace(character)) {
+ if (isAppropriateEndTag()) {
+ if (commitToPartialEndTag(source, character, BeforeAttributeNameState))
+ return true;
+ SWITCH_TO(BeforeAttributeNameState);
}
- bufferCharacter('<');
- bufferCharacter('/');
- m_token->appendToCharacter(m_temporaryBuffer);
- m_bufferedEndTagName.clear();
- m_temporaryBuffer.clear();
- HTML_RECONSUME_IN(RAWTEXTState);
+ } else if (character == '/') {
+ if (isAppropriateEndTag()) {
+ if (commitToPartialEndTag(source, '/', SelfClosingStartTagState))
+ return true;
+ SWITCH_TO(SelfClosingStartTagState);
+ }
+ } else if (character == '>') {
+ if (isAppropriateEndTag())
+ return commitToCompleteEndTag(source);
}
- }
+ bufferASCIICharacter('<');
+ bufferASCIICharacter('/');
+ m_token.appendToCharacter(m_temporaryBuffer);
+ m_bufferedEndTagName.clear();
+ m_temporaryBuffer.clear();
+ RECONSUME_IN(RAWTEXTState);
END_STATE()
- HTML_BEGIN_STATE(ScriptDataLessThanSignState) {
- if (cc == '/') {
+ BEGIN_STATE(ScriptDataLessThanSignState)
+ if (character == '/') {
m_temporaryBuffer.clear();
ASSERT(m_bufferedEndTagName.isEmpty());
- HTML_ADVANCE_TO(ScriptDataEndTagOpenState);
- } else if (cc == '!') {
- bufferCharacter('<');
- bufferCharacter('!');
- HTML_ADVANCE_TO(ScriptDataEscapeStartState);
- } else {
- bufferCharacter('<');
- HTML_RECONSUME_IN(ScriptDataState);
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataEndTagOpenState);
}
- }
+ if (character == '!') {
+ bufferASCIICharacter('<');
+ bufferASCIICharacter('!');
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataEscapeStartState);
+ }
+ bufferASCIICharacter('<');
+ RECONSUME_IN(ScriptDataState);
END_STATE()
- HTML_BEGIN_STATE(ScriptDataEndTagOpenState) {
- if (isASCIIUpper(cc)) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
- HTML_ADVANCE_TO(ScriptDataEndTagNameState);
- } else if (isASCIILower(cc)) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- addToPossibleEndTag(static_cast<LChar>(cc));
- HTML_ADVANCE_TO(ScriptDataEndTagNameState);
- } else {
- bufferCharacter('<');
- bufferCharacter('/');
- HTML_RECONSUME_IN(ScriptDataState);
+ BEGIN_STATE(ScriptDataEndTagOpenState)
+ if (isASCIIAlpha(character)) {
+ appendToTemporaryBuffer(character);
+ appendToPossibleEndTag(convertASCIIAlphaToLower(character));
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataEndTagNameState);
}
- }
+ bufferASCIICharacter('<');
+ bufferASCIICharacter('/');
+ RECONSUME_IN(ScriptDataState);
END_STATE()
- HTML_BEGIN_STATE(ScriptDataEndTagNameState) {
- if (isASCIIUpper(cc)) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
- HTML_ADVANCE_TO(ScriptDataEndTagNameState);
- } else if (isASCIILower(cc)) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- addToPossibleEndTag(static_cast<LChar>(cc));
- HTML_ADVANCE_TO(ScriptDataEndTagNameState);
- } else {
- if (isTokenizerWhitespace(cc)) {
- if (isAppropriateEndTag()) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- FLUSH_AND_ADVANCE_TO(BeforeAttributeNameState);
- }
- } else if (cc == '/') {
- if (isAppropriateEndTag()) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- FLUSH_AND_ADVANCE_TO(SelfClosingStartTagState);
- }
- } else if (cc == '>') {
- if (isAppropriateEndTag()) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- return flushEmitAndResumeIn(source, HTMLTokenizer::DataState);
- }
+ BEGIN_STATE(ScriptDataEndTagNameState)
+ if (isASCIIAlpha(character)) {
+ appendToTemporaryBuffer(character);
+ appendToPossibleEndTag(convertASCIIAlphaToLower(character));
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataEndTagNameState);
+ }
+ if (isTokenizerWhitespace(character)) {
+ if (isAppropriateEndTag()) {
+ if (commitToPartialEndTag(source, character, BeforeAttributeNameState))
+ return true;
+ SWITCH_TO(BeforeAttributeNameState);
}
- bufferCharacter('<');
- bufferCharacter('/');
- m_token->appendToCharacter(m_temporaryBuffer);
- m_bufferedEndTagName.clear();
- m_temporaryBuffer.clear();
- HTML_RECONSUME_IN(ScriptDataState);
+ } else if (character == '/') {
+ if (isAppropriateEndTag()) {
+ if (commitToPartialEndTag(source, '/', SelfClosingStartTagState))
+ return true;
+ SWITCH_TO(SelfClosingStartTagState);
+ }
+ } else if (character == '>') {
+ if (isAppropriateEndTag())
+ return commitToCompleteEndTag(source);
}
- }
+ bufferASCIICharacter('<');
+ bufferASCIICharacter('/');
+ m_token.appendToCharacter(m_temporaryBuffer);
+ m_bufferedEndTagName.clear();
+ m_temporaryBuffer.clear();
+ RECONSUME_IN(ScriptDataState);
END_STATE()
- HTML_BEGIN_STATE(ScriptDataEscapeStartState) {
- if (cc == '-') {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataEscapeStartDashState);
+ BEGIN_STATE(ScriptDataEscapeStartState)
+ if (character == '-') {
+ bufferASCIICharacter('-');
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataEscapeStartDashState);
} else
- HTML_RECONSUME_IN(ScriptDataState);
- }
+ RECONSUME_IN(ScriptDataState);
END_STATE()
- HTML_BEGIN_STATE(ScriptDataEscapeStartDashState) {
- if (cc == '-') {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataEscapedDashDashState);
+ BEGIN_STATE(ScriptDataEscapeStartDashState)
+ if (character == '-') {
+ bufferASCIICharacter('-');
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataEscapedDashDashState);
} else
- HTML_RECONSUME_IN(ScriptDataState);
- }
+ RECONSUME_IN(ScriptDataState);
END_STATE()
- HTML_BEGIN_STATE(ScriptDataEscapedState) {
- if (cc == '-') {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataEscapedDashState);
- } else if (cc == '<')
- HTML_ADVANCE_TO(ScriptDataEscapedLessThanSignState);
- else if (cc == kEndOfFileMarker) {
+ BEGIN_STATE(ScriptDataEscapedState)
+ if (character == '-') {
+ bufferASCIICharacter('-');
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataEscapedDashState);
+ }
+ if (character == '<')
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataEscapedLessThanSignState);
+ if (character == kEndOfFileMarker) {
parseError();
- HTML_RECONSUME_IN(DataState);
- } else {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataEscapedState);
+ RECONSUME_IN(DataState);
}
- }
+ bufferCharacter(character);
+ ADVANCE_TO(ScriptDataEscapedState);
END_STATE()
- HTML_BEGIN_STATE(ScriptDataEscapedDashState) {
- if (cc == '-') {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataEscapedDashDashState);
- } else if (cc == '<')
- HTML_ADVANCE_TO(ScriptDataEscapedLessThanSignState);
- else if (cc == kEndOfFileMarker) {
+ BEGIN_STATE(ScriptDataEscapedDashState)
+ if (character == '-') {
+ bufferASCIICharacter('-');
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataEscapedDashDashState);
+ }
+ if (character == '<')
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataEscapedLessThanSignState);
+ if (character == kEndOfFileMarker) {
parseError();
- HTML_RECONSUME_IN(DataState);
- } else {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataEscapedState);
+ RECONSUME_IN(DataState);
}
- }
+ bufferCharacter(character);
+ ADVANCE_TO(ScriptDataEscapedState);
END_STATE()
- HTML_BEGIN_STATE(ScriptDataEscapedDashDashState) {
- if (cc == '-') {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataEscapedDashDashState);
- } else if (cc == '<')
- HTML_ADVANCE_TO(ScriptDataEscapedLessThanSignState);
- else if (cc == '>') {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataState);
- } else if (cc == kEndOfFileMarker) {
+ BEGIN_STATE(ScriptDataEscapedDashDashState)
+ if (character == '-') {
+ bufferASCIICharacter('-');
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataEscapedDashDashState);
+ }
+ if (character == '<')
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataEscapedLessThanSignState);
+ if (character == '>') {
+ bufferASCIICharacter('>');
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataState);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- HTML_RECONSUME_IN(DataState);
- } else {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataEscapedState);
+ RECONSUME_IN(DataState);
}
- }
+ bufferCharacter(character);
+ ADVANCE_TO(ScriptDataEscapedState);
END_STATE()
- HTML_BEGIN_STATE(ScriptDataEscapedLessThanSignState) {
- if (cc == '/') {
+ BEGIN_STATE(ScriptDataEscapedLessThanSignState)
+ if (character == '/') {
m_temporaryBuffer.clear();
ASSERT(m_bufferedEndTagName.isEmpty());
- HTML_ADVANCE_TO(ScriptDataEscapedEndTagOpenState);
- } else if (isASCIIUpper(cc)) {
- bufferCharacter('<');
- bufferCharacter(cc);
- m_temporaryBuffer.clear();
- m_temporaryBuffer.append(toLowerCase(cc));
- HTML_ADVANCE_TO(ScriptDataDoubleEscapeStartState);
- } else if (isASCIILower(cc)) {
- bufferCharacter('<');
- bufferCharacter(cc);
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataEscapedEndTagOpenState);
+ }
+ if (isASCIIAlpha(character)) {
+ bufferASCIICharacter('<');
+ bufferASCIICharacter(character);
m_temporaryBuffer.clear();
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- HTML_ADVANCE_TO(ScriptDataDoubleEscapeStartState);
- } else {
- bufferCharacter('<');
- HTML_RECONSUME_IN(ScriptDataEscapedState);
+ appendToTemporaryBuffer(convertASCIIAlphaToLower(character));
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataDoubleEscapeStartState);
}
- }
+ bufferASCIICharacter('<');
+ RECONSUME_IN(ScriptDataEscapedState);
END_STATE()
- HTML_BEGIN_STATE(ScriptDataEscapedEndTagOpenState) {
- if (isASCIIUpper(cc)) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
- HTML_ADVANCE_TO(ScriptDataEscapedEndTagNameState);
- } else if (isASCIILower(cc)) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- addToPossibleEndTag(static_cast<LChar>(cc));
- HTML_ADVANCE_TO(ScriptDataEscapedEndTagNameState);
- } else {
- bufferCharacter('<');
- bufferCharacter('/');
- HTML_RECONSUME_IN(ScriptDataEscapedState);
+ BEGIN_STATE(ScriptDataEscapedEndTagOpenState)
+ if (isASCIIAlpha(character)) {
+ appendToTemporaryBuffer(character);
+ appendToPossibleEndTag(convertASCIIAlphaToLower(character));
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataEscapedEndTagNameState);
}
- }
+ bufferASCIICharacter('<');
+ bufferASCIICharacter('/');
+ RECONSUME_IN(ScriptDataEscapedState);
END_STATE()
- HTML_BEGIN_STATE(ScriptDataEscapedEndTagNameState) {
- if (isASCIIUpper(cc)) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- addToPossibleEndTag(static_cast<LChar>(toLowerCase(cc)));
- HTML_ADVANCE_TO(ScriptDataEscapedEndTagNameState);
- } else if (isASCIILower(cc)) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- addToPossibleEndTag(static_cast<LChar>(cc));
- HTML_ADVANCE_TO(ScriptDataEscapedEndTagNameState);
- } else {
- if (isTokenizerWhitespace(cc)) {
- if (isAppropriateEndTag()) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- FLUSH_AND_ADVANCE_TO(BeforeAttributeNameState);
- }
- } else if (cc == '/') {
- if (isAppropriateEndTag()) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- FLUSH_AND_ADVANCE_TO(SelfClosingStartTagState);
- }
- } else if (cc == '>') {
- if (isAppropriateEndTag()) {
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- return flushEmitAndResumeIn(source, HTMLTokenizer::DataState);
- }
+ BEGIN_STATE(ScriptDataEscapedEndTagNameState)
+ if (isASCIIAlpha(character)) {
+ appendToTemporaryBuffer(character);
+ appendToPossibleEndTag(convertASCIIAlphaToLower(character));
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataEscapedEndTagNameState);
+ }
+ if (isTokenizerWhitespace(character)) {
+ if (isAppropriateEndTag()) {
+ if (commitToPartialEndTag(source, character, BeforeAttributeNameState))
+ return true;
+ SWITCH_TO(BeforeAttributeNameState);
}
- bufferCharacter('<');
- bufferCharacter('/');
- m_token->appendToCharacter(m_temporaryBuffer);
- m_bufferedEndTagName.clear();
- m_temporaryBuffer.clear();
- HTML_RECONSUME_IN(ScriptDataEscapedState);
+ } else if (character == '/') {
+ if (isAppropriateEndTag()) {
+ if (commitToPartialEndTag(source, '/', SelfClosingStartTagState))
+ return true;
+ SWITCH_TO(SelfClosingStartTagState);
+ }
+ } else if (character == '>') {
+ if (isAppropriateEndTag())
+ return commitToCompleteEndTag(source);
}
- }
+ bufferASCIICharacter('<');
+ bufferASCIICharacter('/');
+ m_token.appendToCharacter(m_temporaryBuffer);
+ m_bufferedEndTagName.clear();
+ m_temporaryBuffer.clear();
+ RECONSUME_IN(ScriptDataEscapedState);
END_STATE()
- HTML_BEGIN_STATE(ScriptDataDoubleEscapeStartState) {
- if (isTokenizerWhitespace(cc) || cc == '/' || cc == '>') {
- bufferCharacter(cc);
- if (temporaryBufferIs(scriptTag.localName()))
- HTML_ADVANCE_TO(ScriptDataDoubleEscapedState);
+ BEGIN_STATE(ScriptDataDoubleEscapeStartState)
+ if (isTokenizerWhitespace(character) || character == '/' || character == '>') {
+ bufferASCIICharacter(character);
+ if (temporaryBufferIs("script"))
+ ADVANCE_TO(ScriptDataDoubleEscapedState);
else
- HTML_ADVANCE_TO(ScriptDataEscapedState);
- } else if (isASCIIUpper(cc)) {
- bufferCharacter(cc);
- m_temporaryBuffer.append(toLowerCase(cc));
- HTML_ADVANCE_TO(ScriptDataDoubleEscapeStartState);
- } else if (isASCIILower(cc)) {
- bufferCharacter(cc);
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- HTML_ADVANCE_TO(ScriptDataDoubleEscapeStartState);
- } else
- HTML_RECONSUME_IN(ScriptDataEscapedState);
- }
+ ADVANCE_TO(ScriptDataEscapedState);
+ }
+ if (isASCIIAlpha(character)) {
+ bufferASCIICharacter(character);
+ appendToTemporaryBuffer(convertASCIIAlphaToLower(character));
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataDoubleEscapeStartState);
+ }
+ RECONSUME_IN(ScriptDataEscapedState);
END_STATE()
- HTML_BEGIN_STATE(ScriptDataDoubleEscapedState) {
- if (cc == '-') {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataDoubleEscapedDashState);
- } else if (cc == '<') {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataDoubleEscapedLessThanSignState);
- } else if (cc == kEndOfFileMarker) {
+ BEGIN_STATE(ScriptDataDoubleEscapedState)
+ if (character == '-') {
+ bufferASCIICharacter('-');
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataDoubleEscapedDashState);
+ }
+ if (character == '<') {
+ bufferASCIICharacter('<');
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataDoubleEscapedLessThanSignState);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- HTML_RECONSUME_IN(DataState);
- } else {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataDoubleEscapedState);
+ RECONSUME_IN(DataState);
}
- }
+ bufferCharacter(character);
+ ADVANCE_TO(ScriptDataDoubleEscapedState);
END_STATE()
- HTML_BEGIN_STATE(ScriptDataDoubleEscapedDashState) {
- if (cc == '-') {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataDoubleEscapedDashDashState);
- } else if (cc == '<') {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataDoubleEscapedLessThanSignState);
- } else if (cc == kEndOfFileMarker) {
+ BEGIN_STATE(ScriptDataDoubleEscapedDashState)
+ if (character == '-') {
+ bufferASCIICharacter('-');
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataDoubleEscapedDashDashState);
+ }
+ if (character == '<') {
+ bufferASCIICharacter('<');
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataDoubleEscapedLessThanSignState);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- HTML_RECONSUME_IN(DataState);
- } else {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataDoubleEscapedState);
+ RECONSUME_IN(DataState);
}
- }
+ bufferCharacter(character);
+ ADVANCE_TO(ScriptDataDoubleEscapedState);
END_STATE()
- HTML_BEGIN_STATE(ScriptDataDoubleEscapedDashDashState) {
- if (cc == '-') {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataDoubleEscapedDashDashState);
- } else if (cc == '<') {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataDoubleEscapedLessThanSignState);
- } else if (cc == '>') {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataState);
- } else if (cc == kEndOfFileMarker) {
+ BEGIN_STATE(ScriptDataDoubleEscapedDashDashState)
+ if (character == '-') {
+ bufferASCIICharacter('-');
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataDoubleEscapedDashDashState);
+ }
+ if (character == '<') {
+ bufferASCIICharacter('<');
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataDoubleEscapedLessThanSignState);
+ }
+ if (character == '>') {
+ bufferASCIICharacter('>');
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataState);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- HTML_RECONSUME_IN(DataState);
- } else {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(ScriptDataDoubleEscapedState);
+ RECONSUME_IN(DataState);
}
- }
+ bufferCharacter(character);
+ ADVANCE_TO(ScriptDataDoubleEscapedState);
END_STATE()
- HTML_BEGIN_STATE(ScriptDataDoubleEscapedLessThanSignState) {
- if (cc == '/') {
- bufferCharacter(cc);
+ BEGIN_STATE(ScriptDataDoubleEscapedLessThanSignState)
+ if (character == '/') {
+ bufferASCIICharacter('/');
m_temporaryBuffer.clear();
- HTML_ADVANCE_TO(ScriptDataDoubleEscapeEndState);
- } else
- HTML_RECONSUME_IN(ScriptDataDoubleEscapedState);
- }
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataDoubleEscapeEndState);
+ }
+ RECONSUME_IN(ScriptDataDoubleEscapedState);
END_STATE()
- HTML_BEGIN_STATE(ScriptDataDoubleEscapeEndState) {
- if (isTokenizerWhitespace(cc) || cc == '/' || cc == '>') {
- bufferCharacter(cc);
- if (temporaryBufferIs(scriptTag.localName()))
- HTML_ADVANCE_TO(ScriptDataEscapedState);
+ BEGIN_STATE(ScriptDataDoubleEscapeEndState)
+ if (isTokenizerWhitespace(character) || character == '/' || character == '>') {
+ bufferASCIICharacter(character);
+ if (temporaryBufferIs("script"))
+ ADVANCE_TO(ScriptDataEscapedState);
else
- HTML_ADVANCE_TO(ScriptDataDoubleEscapedState);
- } else if (isASCIIUpper(cc)) {
- bufferCharacter(cc);
- m_temporaryBuffer.append(toLowerCase(cc));
- HTML_ADVANCE_TO(ScriptDataDoubleEscapeEndState);
- } else if (isASCIILower(cc)) {
- bufferCharacter(cc);
- m_temporaryBuffer.append(static_cast<LChar>(cc));
- HTML_ADVANCE_TO(ScriptDataDoubleEscapeEndState);
- } else
- HTML_RECONSUME_IN(ScriptDataDoubleEscapedState);
- }
- END_STATE()
-
- HTML_BEGIN_STATE(BeforeAttributeNameState) {
- if (isTokenizerWhitespace(cc))
- HTML_ADVANCE_TO(BeforeAttributeNameState);
- else if (cc == '/')
- HTML_ADVANCE_TO(SelfClosingStartTagState);
- else if (cc == '>')
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- else if (m_options.usePreHTML5ParserQuirks && cc == '<')
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- else if (isASCIIUpper(cc)) {
- m_token->addNewAttribute();
- m_token->beginAttributeName(source.numberOfCharactersConsumed());
- m_token->appendToAttributeName(toLowerCase(cc));
- HTML_ADVANCE_TO(AttributeNameState);
- } else if (cc == kEndOfFileMarker) {
- parseError();
- HTML_RECONSUME_IN(DataState);
- } else {
- if (cc == '"' || cc == '\'' || cc == '<' || cc == '=')
- parseError();
- m_token->addNewAttribute();
- m_token->beginAttributeName(source.numberOfCharactersConsumed());
- m_token->appendToAttributeName(cc);
- HTML_ADVANCE_TO(AttributeNameState);
+ ADVANCE_TO(ScriptDataDoubleEscapedState);
}
- }
- END_STATE()
-
- HTML_BEGIN_STATE(AttributeNameState) {
- if (isTokenizerWhitespace(cc)) {
- m_token->endAttributeName(source.numberOfCharactersConsumed());
- HTML_ADVANCE_TO(AfterAttributeNameState);
- } else if (cc == '/') {
- m_token->endAttributeName(source.numberOfCharactersConsumed());
- HTML_ADVANCE_TO(SelfClosingStartTagState);
- } else if (cc == '=') {
- m_token->endAttributeName(source.numberOfCharactersConsumed());
- HTML_ADVANCE_TO(BeforeAttributeValueState);
- } else if (cc == '>') {
- m_token->endAttributeName(source.numberOfCharactersConsumed());
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- } else if (m_options.usePreHTML5ParserQuirks && cc == '<') {
- m_token->endAttributeName(source.numberOfCharactersConsumed());
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else if (isASCIIUpper(cc)) {
- m_token->appendToAttributeName(toLowerCase(cc));
- HTML_ADVANCE_TO(AttributeNameState);
- } else if (cc == kEndOfFileMarker) {
- parseError();
- m_token->endAttributeName(source.numberOfCharactersConsumed());
- HTML_RECONSUME_IN(DataState);
- } else {
- if (cc == '"' || cc == '\'' || cc == '<' || cc == '=')
- parseError();
- m_token->appendToAttributeName(cc);
- HTML_ADVANCE_TO(AttributeNameState);
+ if (isASCIIAlpha(character)) {
+ bufferASCIICharacter(character);
+ appendToTemporaryBuffer(convertASCIIAlphaToLower(character));
+ ADVANCE_PAST_NON_NEWLINE_TO(ScriptDataDoubleEscapeEndState);
}
- }
+ RECONSUME_IN(ScriptDataDoubleEscapedState);
END_STATE()
- HTML_BEGIN_STATE(AfterAttributeNameState) {
- if (isTokenizerWhitespace(cc))
- HTML_ADVANCE_TO(AfterAttributeNameState);
- else if (cc == '/')
- HTML_ADVANCE_TO(SelfClosingStartTagState);
- else if (cc == '=')
- HTML_ADVANCE_TO(BeforeAttributeValueState);
- else if (cc == '>')
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- else if (m_options.usePreHTML5ParserQuirks && cc == '<')
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- else if (isASCIIUpper(cc)) {
- m_token->addNewAttribute();
- m_token->beginAttributeName(source.numberOfCharactersConsumed());
- m_token->appendToAttributeName(toLowerCase(cc));
- HTML_ADVANCE_TO(AttributeNameState);
- } else if (cc == kEndOfFileMarker) {
- parseError();
- HTML_RECONSUME_IN(DataState);
- } else {
- if (cc == '"' || cc == '\'' || cc == '<')
- parseError();
- m_token->addNewAttribute();
- m_token->beginAttributeName(source.numberOfCharactersConsumed());
- m_token->appendToAttributeName(cc);
- HTML_ADVANCE_TO(AttributeNameState);
+ BEGIN_STATE(BeforeAttributeNameState)
+ if (isTokenizerWhitespace(character))
+ ADVANCE_TO(BeforeAttributeNameState);
+ if (character == '/')
+ ADVANCE_PAST_NON_NEWLINE_TO(SelfClosingStartTagState);
+ if (character == '>')
+ return emitAndResumeInDataState(source);
+ if (m_options.usePreHTML5ParserQuirks && character == '<')
+ return emitAndReconsumeInDataState();
+ if (character == kEndOfFileMarker) {
+ parseError();
+ RECONSUME_IN(DataState);
}
- }
+ if (character == '"' || character == '\'' || character == '<' || character == '=')
+ parseError();
+ m_token.beginAttribute(source.numberOfCharactersConsumed());
+ m_token.appendToAttributeName(toASCIILower(character));
+ ADVANCE_PAST_NON_NEWLINE_TO(AttributeNameState);
+ END_STATE()
+
+ BEGIN_STATE(AttributeNameState)
+ if (isTokenizerWhitespace(character))
+ ADVANCE_TO(AfterAttributeNameState);
+ if (character == '/')
+ ADVANCE_PAST_NON_NEWLINE_TO(SelfClosingStartTagState);
+ if (character == '=')
+ ADVANCE_PAST_NON_NEWLINE_TO(BeforeAttributeValueState);
+ if (character == '>')
+ return emitAndResumeInDataState(source);
+ if (m_options.usePreHTML5ParserQuirks && character == '<')
+ return emitAndReconsumeInDataState();
+ if (character == kEndOfFileMarker) {
+ parseError();
+ RECONSUME_IN(DataState);
+ }
+ if (character == '"' || character == '\'' || character == '<' || character == '=')
+ parseError();
+ m_token.appendToAttributeName(toASCIILower(character));
+ ADVANCE_PAST_NON_NEWLINE_TO(AttributeNameState);
+ END_STATE()
+
+ BEGIN_STATE(AfterAttributeNameState)
+ if (isTokenizerWhitespace(character))
+ ADVANCE_TO(AfterAttributeNameState);
+ if (character == '/')
+ ADVANCE_PAST_NON_NEWLINE_TO(SelfClosingStartTagState);
+ if (character == '=')
+ ADVANCE_PAST_NON_NEWLINE_TO(BeforeAttributeValueState);
+ if (character == '>')
+ return emitAndResumeInDataState(source);
+ if (m_options.usePreHTML5ParserQuirks && character == '<')
+ return emitAndReconsumeInDataState();
+ if (character == kEndOfFileMarker) {
+ parseError();
+ RECONSUME_IN(DataState);
+ }
+ if (character == '"' || character == '\'' || character == '<')
+ parseError();
+ m_token.beginAttribute(source.numberOfCharactersConsumed());
+ m_token.appendToAttributeName(toASCIILower(character));
+ ADVANCE_PAST_NON_NEWLINE_TO(AttributeNameState);
END_STATE()
- HTML_BEGIN_STATE(BeforeAttributeValueState) {
- if (isTokenizerWhitespace(cc))
- HTML_ADVANCE_TO(BeforeAttributeValueState);
- else if (cc == '"') {
- m_token->beginAttributeValue(source.numberOfCharactersConsumed() + 1);
- HTML_ADVANCE_TO(AttributeValueDoubleQuotedState);
- } else if (cc == '&') {
- m_token->beginAttributeValue(source.numberOfCharactersConsumed());
- HTML_RECONSUME_IN(AttributeValueUnquotedState);
- } else if (cc == '\'') {
- m_token->beginAttributeValue(source.numberOfCharactersConsumed() + 1);
- HTML_ADVANCE_TO(AttributeValueSingleQuotedState);
- } else if (cc == '>') {
- parseError();
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- } else if (cc == kEndOfFileMarker) {
- parseError();
- HTML_RECONSUME_IN(DataState);
- } else {
- if (cc == '<' || cc == '=' || cc == '`')
- parseError();
- m_token->beginAttributeValue(source.numberOfCharactersConsumed());
- m_token->appendToAttributeValue(cc);
- HTML_ADVANCE_TO(AttributeValueUnquotedState);
+ BEGIN_STATE(BeforeAttributeValueState)
+ if (isTokenizerWhitespace(character))
+ ADVANCE_TO(BeforeAttributeValueState);
+ if (character == '"')
+ ADVANCE_PAST_NON_NEWLINE_TO(AttributeValueDoubleQuotedState);
+ if (character == '&')
+ RECONSUME_IN(AttributeValueUnquotedState);
+ if (character == '\'')
+ ADVANCE_PAST_NON_NEWLINE_TO(AttributeValueSingleQuotedState);
+ if (character == '>') {
+ parseError();
+ return emitAndResumeInDataState(source);
}
- }
+ if (character == kEndOfFileMarker) {
+ parseError();
+ RECONSUME_IN(DataState);
+ }
+ if (character == '<' || character == '=' || character == '`')
+ parseError();
+ m_token.appendToAttributeValue(character);
+ ADVANCE_PAST_NON_NEWLINE_TO(AttributeValueUnquotedState);
END_STATE()
- HTML_BEGIN_STATE(AttributeValueDoubleQuotedState) {
- if (cc == '"') {
- m_token->endAttributeValue(source.numberOfCharactersConsumed());
- HTML_ADVANCE_TO(AfterAttributeValueQuotedState);
- } else if (cc == '&') {
+ BEGIN_STATE(AttributeValueDoubleQuotedState)
+ if (character == '"') {
+ m_token.endAttribute(source.numberOfCharactersConsumed());
+ ADVANCE_PAST_NON_NEWLINE_TO(AfterAttributeValueQuotedState);
+ }
+ if (character == '&') {
m_additionalAllowedCharacter = '"';
- HTML_ADVANCE_TO(CharacterReferenceInAttributeValueState);
- } else if (cc == kEndOfFileMarker) {
+ ADVANCE_PAST_NON_NEWLINE_TO(CharacterReferenceInAttributeValueState);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- m_token->endAttributeValue(source.numberOfCharactersConsumed());
- HTML_RECONSUME_IN(DataState);
- } else {
- m_token->appendToAttributeValue(cc);
- HTML_ADVANCE_TO(AttributeValueDoubleQuotedState);
+ m_token.endAttribute(source.numberOfCharactersConsumed());
+ RECONSUME_IN(DataState);
}
- }
+ m_token.appendToAttributeValue(character);
+ ADVANCE_TO(AttributeValueDoubleQuotedState);
END_STATE()
- HTML_BEGIN_STATE(AttributeValueSingleQuotedState) {
- if (cc == '\'') {
- m_token->endAttributeValue(source.numberOfCharactersConsumed());
- HTML_ADVANCE_TO(AfterAttributeValueQuotedState);
- } else if (cc == '&') {
+ BEGIN_STATE(AttributeValueSingleQuotedState)
+ if (character == '\'') {
+ m_token.endAttribute(source.numberOfCharactersConsumed());
+ ADVANCE_PAST_NON_NEWLINE_TO(AfterAttributeValueQuotedState);
+ }
+ if (character == '&') {
m_additionalAllowedCharacter = '\'';
- HTML_ADVANCE_TO(CharacterReferenceInAttributeValueState);
- } else if (cc == kEndOfFileMarker) {
+ ADVANCE_PAST_NON_NEWLINE_TO(CharacterReferenceInAttributeValueState);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- m_token->endAttributeValue(source.numberOfCharactersConsumed());
- HTML_RECONSUME_IN(DataState);
- } else {
- m_token->appendToAttributeValue(cc);
- HTML_ADVANCE_TO(AttributeValueSingleQuotedState);
+ m_token.endAttribute(source.numberOfCharactersConsumed());
+ RECONSUME_IN(DataState);
}
- }
+ m_token.appendToAttributeValue(character);
+ ADVANCE_TO(AttributeValueSingleQuotedState);
END_STATE()
- HTML_BEGIN_STATE(AttributeValueUnquotedState) {
- if (isTokenizerWhitespace(cc)) {
- m_token->endAttributeValue(source.numberOfCharactersConsumed());
- HTML_ADVANCE_TO(BeforeAttributeNameState);
- } else if (cc == '&') {
+ BEGIN_STATE(AttributeValueUnquotedState)
+ if (isTokenizerWhitespace(character)) {
+ m_token.endAttribute(source.numberOfCharactersConsumed());
+ ADVANCE_TO(BeforeAttributeNameState);
+ }
+ if (character == '&') {
m_additionalAllowedCharacter = '>';
- HTML_ADVANCE_TO(CharacterReferenceInAttributeValueState);
- } else if (cc == '>') {
- m_token->endAttributeValue(source.numberOfCharactersConsumed());
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- } else if (cc == kEndOfFileMarker) {
- parseError();
- m_token->endAttributeValue(source.numberOfCharactersConsumed());
- HTML_RECONSUME_IN(DataState);
- } else {
- if (cc == '"' || cc == '\'' || cc == '<' || cc == '=' || cc == '`')
- parseError();
- m_token->appendToAttributeValue(cc);
- HTML_ADVANCE_TO(AttributeValueUnquotedState);
+ ADVANCE_PAST_NON_NEWLINE_TO(CharacterReferenceInAttributeValueState);
}
- }
+ if (character == '>') {
+ m_token.endAttribute(source.numberOfCharactersConsumed());
+ return emitAndResumeInDataState(source);
+ }
+ if (character == kEndOfFileMarker) {
+ parseError();
+ m_token.endAttribute(source.numberOfCharactersConsumed());
+ RECONSUME_IN(DataState);
+ }
+ if (character == '"' || character == '\'' || character == '<' || character == '=' || character == '`')
+ parseError();
+ m_token.appendToAttributeValue(character);
+ ADVANCE_PAST_NON_NEWLINE_TO(AttributeValueUnquotedState);
END_STATE()
- HTML_BEGIN_STATE(CharacterReferenceInAttributeValueState) {
+ BEGIN_STATE(CharacterReferenceInAttributeValueState)
bool notEnoughCharacters = false;
StringBuilder decodedEntity;
bool success = consumeHTMLEntity(source, decodedEntity, notEnoughCharacters, m_additionalAllowedCharacter);
if (notEnoughCharacters)
- return haveBufferedCharacterToken();
+ RETURN_IN_CURRENT_STATE(haveBufferedCharacterToken());
if (!success) {
ASSERT(decodedEntity.isEmpty());
- m_token->appendToAttributeValue('&');
+ m_token.appendToAttributeValue('&');
} else {
for (unsigned i = 0; i < decodedEntity.length(); ++i)
- m_token->appendToAttributeValue(decodedEntity[i]);
+ m_token.appendToAttributeValue(decodedEntity[i]);
}
// We're supposed to switch back to the attribute value state that
// we were in when we were switched into this state. Rather than
// keeping track of this explictly, we observe that the previous
// state can be determined by m_additionalAllowedCharacter.
if (m_additionalAllowedCharacter == '"')
- HTML_SWITCH_TO(AttributeValueDoubleQuotedState);
- else if (m_additionalAllowedCharacter == '\'')
- HTML_SWITCH_TO(AttributeValueSingleQuotedState);
- else if (m_additionalAllowedCharacter == '>')
- HTML_SWITCH_TO(AttributeValueUnquotedState);
- else
- ASSERT_NOT_REACHED();
- }
- END_STATE()
-
- HTML_BEGIN_STATE(AfterAttributeValueQuotedState) {
- if (isTokenizerWhitespace(cc))
- HTML_ADVANCE_TO(BeforeAttributeNameState);
- else if (cc == '/')
- HTML_ADVANCE_TO(SelfClosingStartTagState);
- else if (cc == '>')
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- else if (m_options.usePreHTML5ParserQuirks && cc == '<')
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- else if (cc == kEndOfFileMarker) {
- parseError();
- HTML_RECONSUME_IN(DataState);
- } else {
- parseError();
- HTML_RECONSUME_IN(BeforeAttributeNameState);
+ SWITCH_TO(AttributeValueDoubleQuotedState);
+ if (m_additionalAllowedCharacter == '\'')
+ SWITCH_TO(AttributeValueSingleQuotedState);
+ ASSERT(m_additionalAllowedCharacter == '>');
+ SWITCH_TO(AttributeValueUnquotedState);
+ END_STATE()
+
+ BEGIN_STATE(AfterAttributeValueQuotedState)
+ if (isTokenizerWhitespace(character))
+ ADVANCE_TO(BeforeAttributeNameState);
+ if (character == '/')
+ ADVANCE_PAST_NON_NEWLINE_TO(SelfClosingStartTagState);
+ if (character == '>')
+ return emitAndResumeInDataState(source);
+ if (m_options.usePreHTML5ParserQuirks && character == '<')
+ return emitAndReconsumeInDataState();
+ if (character == kEndOfFileMarker) {
+ parseError();
+ RECONSUME_IN(DataState);
}
- }
+ parseError();
+ RECONSUME_IN(BeforeAttributeNameState);
END_STATE()
- HTML_BEGIN_STATE(SelfClosingStartTagState) {
- if (cc == '>') {
- m_token->setSelfClosing();
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- } else if (cc == kEndOfFileMarker) {
- parseError();
- HTML_RECONSUME_IN(DataState);
- } else {
+ BEGIN_STATE(SelfClosingStartTagState)
+ if (character == '>') {
+ m_token.setSelfClosing();
+ return emitAndResumeInDataState(source);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- HTML_RECONSUME_IN(BeforeAttributeNameState);
+ RECONSUME_IN(DataState);
}
- }
+ parseError();
+ RECONSUME_IN(BeforeAttributeNameState);
END_STATE()
- HTML_BEGIN_STATE(BogusCommentState) {
- m_token->beginComment();
- HTML_RECONSUME_IN(ContinueBogusCommentState);
- }
+ BEGIN_STATE(BogusCommentState)
+ m_token.beginComment();
+ RECONSUME_IN(ContinueBogusCommentState);
END_STATE()
- HTML_BEGIN_STATE(ContinueBogusCommentState) {
- if (cc == '>')
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- else if (cc == kEndOfFileMarker)
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- else {
- m_token->appendToComment(cc);
- HTML_ADVANCE_TO(ContinueBogusCommentState);
- }
- }
+ BEGIN_STATE(ContinueBogusCommentState)
+ if (character == '>')
+ return emitAndResumeInDataState(source);
+ if (character == kEndOfFileMarker)
+ return emitAndReconsumeInDataState();
+ m_token.appendToComment(character);
+ ADVANCE_TO(ContinueBogusCommentState);
END_STATE()
- HTML_BEGIN_STATE(MarkupDeclarationOpenState) {
- DEFINE_STATIC_LOCAL(String, dashDashString, (ASCIILiteral("--")));
- DEFINE_STATIC_LOCAL(String, doctypeString, (ASCIILiteral("doctype")));
- DEFINE_STATIC_LOCAL(String, cdataString, (ASCIILiteral("[CDATA[")));
- if (cc == '-') {
- SegmentedString::LookAheadResult result = source.lookAhead(dashDashString);
- if (result == SegmentedString::DidMatch) {
- source.advanceAndASSERT('-');
- source.advanceAndASSERT('-');
- m_token->beginComment();
- HTML_SWITCH_TO(CommentStartState);
- } else if (result == SegmentedString::NotEnoughCharacters)
- return haveBufferedCharacterToken();
- } else if (cc == 'D' || cc == 'd') {
- SegmentedString::LookAheadResult result = source.lookAheadIgnoringCase(doctypeString);
+ BEGIN_STATE(MarkupDeclarationOpenState)
+ if (character == '-') {
+ auto result = source.advancePast("--");
if (result == SegmentedString::DidMatch) {
- advanceStringAndASSERTIgnoringCase(source, "doctype");
- HTML_SWITCH_TO(DOCTYPEState);
- } else if (result == SegmentedString::NotEnoughCharacters)
- return haveBufferedCharacterToken();
- } else if (cc == '[' && shouldAllowCDATA()) {
- SegmentedString::LookAheadResult result = source.lookAhead(cdataString);
- if (result == SegmentedString::DidMatch) {
- advanceStringAndASSERT(source, "[CDATA[");
- HTML_SWITCH_TO(CDATASectionState);
- } else if (result == SegmentedString::NotEnoughCharacters)
- return haveBufferedCharacterToken();
+ m_token.beginComment();
+ SWITCH_TO(CommentStartState);
+ }
+ if (result == SegmentedString::NotEnoughCharacters)
+ RETURN_IN_CURRENT_STATE(haveBufferedCharacterToken());
+ } else if (isASCIIAlphaCaselessEqual(character, 'd')) {
+ auto result = source.advancePastLettersIgnoringASCIICase("doctype");
+ if (result == SegmentedString::DidMatch)
+ SWITCH_TO(DOCTYPEState);
+ if (result == SegmentedString::NotEnoughCharacters)
+ RETURN_IN_CURRENT_STATE(haveBufferedCharacterToken());
+ } else if (character == '[' && shouldAllowCDATA()) {
+ auto result = source.advancePast("[CDATA[");
+ if (result == SegmentedString::DidMatch)
+ SWITCH_TO(CDATASectionState);
+ if (result == SegmentedString::NotEnoughCharacters)
+ RETURN_IN_CURRENT_STATE(haveBufferedCharacterToken());
}
parseError();
- HTML_RECONSUME_IN(BogusCommentState);
- }
+ RECONSUME_IN(BogusCommentState);
END_STATE()
- HTML_BEGIN_STATE(CommentStartState) {
- if (cc == '-')
- HTML_ADVANCE_TO(CommentStartDashState);
- else if (cc == '>') {
+ BEGIN_STATE(CommentStartState)
+ if (character == '-')
+ ADVANCE_PAST_NON_NEWLINE_TO(CommentStartDashState);
+ if (character == '>') {
parseError();
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- } else if (cc == kEndOfFileMarker) {
+ return emitAndResumeInDataState(source);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
- m_token->appendToComment(cc);
- HTML_ADVANCE_TO(CommentState);
+ return emitAndReconsumeInDataState();
}
- }
+ m_token.appendToComment(character);
+ ADVANCE_TO(CommentState);
END_STATE()
- HTML_BEGIN_STATE(CommentStartDashState) {
- if (cc == '-')
- HTML_ADVANCE_TO(CommentEndState);
- else if (cc == '>') {
+ BEGIN_STATE(CommentStartDashState)
+ if (character == '-')
+ ADVANCE_PAST_NON_NEWLINE_TO(CommentEndState);
+ if (character == '>') {
parseError();
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- } else if (cc == kEndOfFileMarker) {
+ return emitAndResumeInDataState(source);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
- m_token->appendToComment('-');
- m_token->appendToComment(cc);
- HTML_ADVANCE_TO(CommentState);
+ return emitAndReconsumeInDataState();
}
- }
+ m_token.appendToComment('-');
+ m_token.appendToComment(character);
+ ADVANCE_TO(CommentState);
END_STATE()
- HTML_BEGIN_STATE(CommentState) {
- if (cc == '-')
- HTML_ADVANCE_TO(CommentEndDashState);
- else if (cc == kEndOfFileMarker) {
+ BEGIN_STATE(CommentState)
+ if (character == '-')
+ ADVANCE_PAST_NON_NEWLINE_TO(CommentEndDashState);
+ if (character == kEndOfFileMarker) {
parseError();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
- m_token->appendToComment(cc);
- HTML_ADVANCE_TO(CommentState);
+ return emitAndReconsumeInDataState();
}
- }
+ m_token.appendToComment(character);
+ ADVANCE_TO(CommentState);
END_STATE()
- HTML_BEGIN_STATE(CommentEndDashState) {
- if (cc == '-')
- HTML_ADVANCE_TO(CommentEndState);
- else if (cc == kEndOfFileMarker) {
+ BEGIN_STATE(CommentEndDashState)
+ if (character == '-')
+ ADVANCE_PAST_NON_NEWLINE_TO(CommentEndState);
+ if (character == kEndOfFileMarker) {
parseError();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
- m_token->appendToComment('-');
- m_token->appendToComment(cc);
- HTML_ADVANCE_TO(CommentState);
+ return emitAndReconsumeInDataState();
}
- }
+ m_token.appendToComment('-');
+ m_token.appendToComment(character);
+ ADVANCE_TO(CommentState);
END_STATE()
- HTML_BEGIN_STATE(CommentEndState) {
- if (cc == '>')
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- else if (cc == '!') {
- parseError();
- HTML_ADVANCE_TO(CommentEndBangState);
- } else if (cc == '-') {
+ BEGIN_STATE(CommentEndState)
+ if (character == '>')
+ return emitAndResumeInDataState(source);
+ if (character == '!') {
parseError();
- m_token->appendToComment('-');
- HTML_ADVANCE_TO(CommentEndState);
- } else if (cc == kEndOfFileMarker) {
+ ADVANCE_PAST_NON_NEWLINE_TO(CommentEndBangState);
+ }
+ if (character == '-') {
parseError();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
+ m_token.appendToComment('-');
+ ADVANCE_PAST_NON_NEWLINE_TO(CommentEndState);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- m_token->appendToComment('-');
- m_token->appendToComment('-');
- m_token->appendToComment(cc);
- HTML_ADVANCE_TO(CommentState);
+ return emitAndReconsumeInDataState();
}
- }
- END_STATE()
-
- HTML_BEGIN_STATE(CommentEndBangState) {
- if (cc == '-') {
- m_token->appendToComment('-');
- m_token->appendToComment('-');
- m_token->appendToComment('!');
- HTML_ADVANCE_TO(CommentEndDashState);
- } else if (cc == '>')
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- else if (cc == kEndOfFileMarker) {
+ parseError();
+ m_token.appendToComment('-');
+ m_token.appendToComment('-');
+ m_token.appendToComment(character);
+ ADVANCE_TO(CommentState);
+ END_STATE()
+
+ BEGIN_STATE(CommentEndBangState)
+ if (character == '-') {
+ m_token.appendToComment('-');
+ m_token.appendToComment('-');
+ m_token.appendToComment('!');
+ ADVANCE_PAST_NON_NEWLINE_TO(CommentEndDashState);
+ }
+ if (character == '>')
+ return emitAndResumeInDataState(source);
+ if (character == kEndOfFileMarker) {
parseError();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
- m_token->appendToComment('-');
- m_token->appendToComment('-');
- m_token->appendToComment('!');
- m_token->appendToComment(cc);
- HTML_ADVANCE_TO(CommentState);
+ return emitAndReconsumeInDataState();
}
- }
+ m_token.appendToComment('-');
+ m_token.appendToComment('-');
+ m_token.appendToComment('!');
+ m_token.appendToComment(character);
+ ADVANCE_TO(CommentState);
END_STATE()
- HTML_BEGIN_STATE(DOCTYPEState) {
- if (isTokenizerWhitespace(cc))
- HTML_ADVANCE_TO(BeforeDOCTYPENameState);
- else if (cc == kEndOfFileMarker) {
+ BEGIN_STATE(DOCTYPEState)
+ if (isTokenizerWhitespace(character))
+ ADVANCE_TO(BeforeDOCTYPENameState);
+ if (character == kEndOfFileMarker) {
parseError();
- m_token->beginDOCTYPE();
- m_token->setForceQuirks();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
- parseError();
- HTML_RECONSUME_IN(BeforeDOCTYPENameState);
+ m_token.beginDOCTYPE();
+ m_token.setForceQuirks();
+ return emitAndReconsumeInDataState();
}
- }
+ parseError();
+ RECONSUME_IN(BeforeDOCTYPENameState);
END_STATE()
- HTML_BEGIN_STATE(BeforeDOCTYPENameState) {
- if (isTokenizerWhitespace(cc))
- HTML_ADVANCE_TO(BeforeDOCTYPENameState);
- else if (isASCIIUpper(cc)) {
- m_token->beginDOCTYPE(toLowerCase(cc));
- HTML_ADVANCE_TO(DOCTYPENameState);
- } else if (cc == '>') {
+ BEGIN_STATE(BeforeDOCTYPENameState)
+ if (isTokenizerWhitespace(character))
+ ADVANCE_TO(BeforeDOCTYPENameState);
+ if (character == '>') {
parseError();
- m_token->beginDOCTYPE();
- m_token->setForceQuirks();
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- } else if (cc == kEndOfFileMarker) {
+ m_token.beginDOCTYPE();
+ m_token.setForceQuirks();
+ return emitAndResumeInDataState(source);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- m_token->beginDOCTYPE();
- m_token->setForceQuirks();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
- m_token->beginDOCTYPE(cc);
- HTML_ADVANCE_TO(DOCTYPENameState);
+ m_token.beginDOCTYPE();
+ m_token.setForceQuirks();
+ return emitAndReconsumeInDataState();
}
- }
+ m_token.beginDOCTYPE(toASCIILower(character));
+ ADVANCE_PAST_NON_NEWLINE_TO(DOCTYPENameState);
END_STATE()
- HTML_BEGIN_STATE(DOCTYPENameState) {
- if (isTokenizerWhitespace(cc))
- HTML_ADVANCE_TO(AfterDOCTYPENameState);
- else if (cc == '>')
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- else if (isASCIIUpper(cc)) {
- m_token->appendToName(toLowerCase(cc));
- HTML_ADVANCE_TO(DOCTYPENameState);
- } else if (cc == kEndOfFileMarker) {
+ BEGIN_STATE(DOCTYPENameState)
+ if (isTokenizerWhitespace(character))
+ ADVANCE_TO(AfterDOCTYPENameState);
+ if (character == '>')
+ return emitAndResumeInDataState(source);
+ if (character == kEndOfFileMarker) {
parseError();
- m_token->setForceQuirks();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
- m_token->appendToName(cc);
- HTML_ADVANCE_TO(DOCTYPENameState);
+ m_token.setForceQuirks();
+ return emitAndReconsumeInDataState();
}
- }
+ m_token.appendToName(toASCIILower(character));
+ ADVANCE_PAST_NON_NEWLINE_TO(DOCTYPENameState);
END_STATE()
- HTML_BEGIN_STATE(AfterDOCTYPENameState) {
- if (isTokenizerWhitespace(cc))
- HTML_ADVANCE_TO(AfterDOCTYPENameState);
- if (cc == '>')
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- else if (cc == kEndOfFileMarker) {
+ BEGIN_STATE(AfterDOCTYPENameState)
+ if (isTokenizerWhitespace(character))
+ ADVANCE_TO(AfterDOCTYPENameState);
+ if (character == '>')
+ return emitAndResumeInDataState(source);
+ if (character == kEndOfFileMarker) {
parseError();
- m_token->setForceQuirks();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
- DEFINE_STATIC_LOCAL(String, publicString, (ASCIILiteral("public")));
- DEFINE_STATIC_LOCAL(String, systemString, (ASCIILiteral("system")));
- if (cc == 'P' || cc == 'p') {
- SegmentedString::LookAheadResult result = source.lookAheadIgnoringCase(publicString);
- if (result == SegmentedString::DidMatch) {
- advanceStringAndASSERTIgnoringCase(source, "public");
- HTML_SWITCH_TO(AfterDOCTYPEPublicKeywordState);
- } else if (result == SegmentedString::NotEnoughCharacters)
- return haveBufferedCharacterToken();
- } else if (cc == 'S' || cc == 's') {
- SegmentedString::LookAheadResult result = source.lookAheadIgnoringCase(systemString);
- if (result == SegmentedString::DidMatch) {
- advanceStringAndASSERTIgnoringCase(source, "system");
- HTML_SWITCH_TO(AfterDOCTYPESystemKeywordState);
- } else if (result == SegmentedString::NotEnoughCharacters)
- return haveBufferedCharacterToken();
- }
- parseError();
- m_token->setForceQuirks();
- HTML_ADVANCE_TO(BogusDOCTYPEState);
+ m_token.setForceQuirks();
+ return emitAndReconsumeInDataState();
}
- }
+ if (isASCIIAlphaCaselessEqual(character, 'p')) {
+ auto result = source.advancePastLettersIgnoringASCIICase("public");
+ if (result == SegmentedString::DidMatch)
+ SWITCH_TO(AfterDOCTYPEPublicKeywordState);
+ if (result == SegmentedString::NotEnoughCharacters)
+ RETURN_IN_CURRENT_STATE(haveBufferedCharacterToken());
+ } else if (isASCIIAlphaCaselessEqual(character, 's')) {
+ auto result = source.advancePastLettersIgnoringASCIICase("system");
+ if (result == SegmentedString::DidMatch)
+ SWITCH_TO(AfterDOCTYPESystemKeywordState);
+ if (result == SegmentedString::NotEnoughCharacters)
+ RETURN_IN_CURRENT_STATE(haveBufferedCharacterToken());
+ }
+ parseError();
+ m_token.setForceQuirks();
+ ADVANCE_PAST_NON_NEWLINE_TO(BogusDOCTYPEState);
END_STATE()
- HTML_BEGIN_STATE(AfterDOCTYPEPublicKeywordState) {
- if (isTokenizerWhitespace(cc))
- HTML_ADVANCE_TO(BeforeDOCTYPEPublicIdentifierState);
- else if (cc == '"') {
- parseError();
- m_token->setPublicIdentifierToEmptyString();
- HTML_ADVANCE_TO(DOCTYPEPublicIdentifierDoubleQuotedState);
- } else if (cc == '\'') {
+ BEGIN_STATE(AfterDOCTYPEPublicKeywordState)
+ if (isTokenizerWhitespace(character))
+ ADVANCE_TO(BeforeDOCTYPEPublicIdentifierState);
+ if (character == '"') {
parseError();
- m_token->setPublicIdentifierToEmptyString();
- HTML_ADVANCE_TO(DOCTYPEPublicIdentifierSingleQuotedState);
- } else if (cc == '>') {
+ m_token.setPublicIdentifierToEmptyString();
+ ADVANCE_PAST_NON_NEWLINE_TO(DOCTYPEPublicIdentifierDoubleQuotedState);
+ }
+ if (character == '\'') {
parseError();
- m_token->setForceQuirks();
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- } else if (cc == kEndOfFileMarker) {
+ m_token.setPublicIdentifierToEmptyString();
+ ADVANCE_PAST_NON_NEWLINE_TO(DOCTYPEPublicIdentifierSingleQuotedState);
+ }
+ if (character == '>') {
parseError();
- m_token->setForceQuirks();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
+ m_token.setForceQuirks();
+ return emitAndResumeInDataState(source);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- m_token->setForceQuirks();
- HTML_ADVANCE_TO(BogusDOCTYPEState);
+ m_token.setForceQuirks();
+ return emitAndReconsumeInDataState();
}
- }
+ parseError();
+ m_token.setForceQuirks();
+ ADVANCE_PAST_NON_NEWLINE_TO(BogusDOCTYPEState);
END_STATE()
- HTML_BEGIN_STATE(BeforeDOCTYPEPublicIdentifierState) {
- if (isTokenizerWhitespace(cc))
- HTML_ADVANCE_TO(BeforeDOCTYPEPublicIdentifierState);
- else if (cc == '"') {
- m_token->setPublicIdentifierToEmptyString();
- HTML_ADVANCE_TO(DOCTYPEPublicIdentifierDoubleQuotedState);
- } else if (cc == '\'') {
- m_token->setPublicIdentifierToEmptyString();
- HTML_ADVANCE_TO(DOCTYPEPublicIdentifierSingleQuotedState);
- } else if (cc == '>') {
- parseError();
- m_token->setForceQuirks();
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- } else if (cc == kEndOfFileMarker) {
+ BEGIN_STATE(BeforeDOCTYPEPublicIdentifierState)
+ if (isTokenizerWhitespace(character))
+ ADVANCE_TO(BeforeDOCTYPEPublicIdentifierState);
+ if (character == '"') {
+ m_token.setPublicIdentifierToEmptyString();
+ ADVANCE_PAST_NON_NEWLINE_TO(DOCTYPEPublicIdentifierDoubleQuotedState);
+ }
+ if (character == '\'') {
+ m_token.setPublicIdentifierToEmptyString();
+ ADVANCE_PAST_NON_NEWLINE_TO(DOCTYPEPublicIdentifierSingleQuotedState);
+ }
+ if (character == '>') {
parseError();
- m_token->setForceQuirks();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
+ m_token.setForceQuirks();
+ return emitAndResumeInDataState(source);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- m_token->setForceQuirks();
- HTML_ADVANCE_TO(BogusDOCTYPEState);
+ m_token.setForceQuirks();
+ return emitAndReconsumeInDataState();
}
- }
+ parseError();
+ m_token.setForceQuirks();
+ ADVANCE_PAST_NON_NEWLINE_TO(BogusDOCTYPEState);
END_STATE()
- HTML_BEGIN_STATE(DOCTYPEPublicIdentifierDoubleQuotedState) {
- if (cc == '"')
- HTML_ADVANCE_TO(AfterDOCTYPEPublicIdentifierState);
- else if (cc == '>') {
+ BEGIN_STATE(DOCTYPEPublicIdentifierDoubleQuotedState)
+ if (character == '"')
+ ADVANCE_PAST_NON_NEWLINE_TO(AfterDOCTYPEPublicIdentifierState);
+ if (character == '>') {
parseError();
- m_token->setForceQuirks();
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- } else if (cc == kEndOfFileMarker) {
+ m_token.setForceQuirks();
+ return emitAndResumeInDataState(source);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- m_token->setForceQuirks();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
- m_token->appendToPublicIdentifier(cc);
- HTML_ADVANCE_TO(DOCTYPEPublicIdentifierDoubleQuotedState);
+ m_token.setForceQuirks();
+ return emitAndReconsumeInDataState();
}
- }
+ m_token.appendToPublicIdentifier(character);
+ ADVANCE_TO(DOCTYPEPublicIdentifierDoubleQuotedState);
END_STATE()
- HTML_BEGIN_STATE(DOCTYPEPublicIdentifierSingleQuotedState) {
- if (cc == '\'')
- HTML_ADVANCE_TO(AfterDOCTYPEPublicIdentifierState);
- else if (cc == '>') {
+ BEGIN_STATE(DOCTYPEPublicIdentifierSingleQuotedState)
+ if (character == '\'')
+ ADVANCE_PAST_NON_NEWLINE_TO(AfterDOCTYPEPublicIdentifierState);
+ if (character == '>') {
parseError();
- m_token->setForceQuirks();
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- } else if (cc == kEndOfFileMarker) {
+ m_token.setForceQuirks();
+ return emitAndResumeInDataState(source);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- m_token->setForceQuirks();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
- m_token->appendToPublicIdentifier(cc);
- HTML_ADVANCE_TO(DOCTYPEPublicIdentifierSingleQuotedState);
+ m_token.setForceQuirks();
+ return emitAndReconsumeInDataState();
}
- }
+ m_token.appendToPublicIdentifier(character);
+ ADVANCE_TO(DOCTYPEPublicIdentifierSingleQuotedState);
END_STATE()
- HTML_BEGIN_STATE(AfterDOCTYPEPublicIdentifierState) {
- if (isTokenizerWhitespace(cc))
- HTML_ADVANCE_TO(BetweenDOCTYPEPublicAndSystemIdentifiersState);
- else if (cc == '>')
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- else if (cc == '"') {
- parseError();
- m_token->setSystemIdentifierToEmptyString();
- HTML_ADVANCE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
- } else if (cc == '\'') {
+ BEGIN_STATE(AfterDOCTYPEPublicIdentifierState)
+ if (isTokenizerWhitespace(character))
+ ADVANCE_TO(BetweenDOCTYPEPublicAndSystemIdentifiersState);
+ if (character == '>')
+ return emitAndResumeInDataState(source);
+ if (character == '"') {
parseError();
- m_token->setSystemIdentifierToEmptyString();
- HTML_ADVANCE_TO(DOCTYPESystemIdentifierSingleQuotedState);
- } else if (cc == kEndOfFileMarker) {
+ m_token.setSystemIdentifierToEmptyString();
+ ADVANCE_PAST_NON_NEWLINE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
+ }
+ if (character == '\'') {
parseError();
- m_token->setForceQuirks();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
+ m_token.setSystemIdentifierToEmptyString();
+ ADVANCE_PAST_NON_NEWLINE_TO(DOCTYPESystemIdentifierSingleQuotedState);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- m_token->setForceQuirks();
- HTML_ADVANCE_TO(BogusDOCTYPEState);
+ m_token.setForceQuirks();
+ return emitAndReconsumeInDataState();
}
- }
- END_STATE()
-
- HTML_BEGIN_STATE(BetweenDOCTYPEPublicAndSystemIdentifiersState) {
- if (isTokenizerWhitespace(cc))
- HTML_ADVANCE_TO(BetweenDOCTYPEPublicAndSystemIdentifiersState);
- else if (cc == '>')
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- else if (cc == '"') {
- m_token->setSystemIdentifierToEmptyString();
- HTML_ADVANCE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
- } else if (cc == '\'') {
- m_token->setSystemIdentifierToEmptyString();
- HTML_ADVANCE_TO(DOCTYPESystemIdentifierSingleQuotedState);
- } else if (cc == kEndOfFileMarker) {
- parseError();
- m_token->setForceQuirks();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
+ parseError();
+ m_token.setForceQuirks();
+ ADVANCE_PAST_NON_NEWLINE_TO(BogusDOCTYPEState);
+ END_STATE()
+
+ BEGIN_STATE(BetweenDOCTYPEPublicAndSystemIdentifiersState)
+ if (isTokenizerWhitespace(character))
+ ADVANCE_TO(BetweenDOCTYPEPublicAndSystemIdentifiersState);
+ if (character == '>')
+ return emitAndResumeInDataState(source);
+ if (character == '"') {
+ m_token.setSystemIdentifierToEmptyString();
+ ADVANCE_PAST_NON_NEWLINE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
+ }
+ if (character == '\'') {
+ m_token.setSystemIdentifierToEmptyString();
+ ADVANCE_PAST_NON_NEWLINE_TO(DOCTYPESystemIdentifierSingleQuotedState);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- m_token->setForceQuirks();
- HTML_ADVANCE_TO(BogusDOCTYPEState);
+ m_token.setForceQuirks();
+ return emitAndReconsumeInDataState();
}
- }
+ parseError();
+ m_token.setForceQuirks();
+ ADVANCE_PAST_NON_NEWLINE_TO(BogusDOCTYPEState);
END_STATE()
- HTML_BEGIN_STATE(AfterDOCTYPESystemKeywordState) {
- if (isTokenizerWhitespace(cc))
- HTML_ADVANCE_TO(BeforeDOCTYPESystemIdentifierState);
- else if (cc == '"') {
+ BEGIN_STATE(AfterDOCTYPESystemKeywordState)
+ if (isTokenizerWhitespace(character))
+ ADVANCE_TO(BeforeDOCTYPESystemIdentifierState);
+ if (character == '"') {
parseError();
- m_token->setSystemIdentifierToEmptyString();
- HTML_ADVANCE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
- } else if (cc == '\'') {
- parseError();
- m_token->setSystemIdentifierToEmptyString();
- HTML_ADVANCE_TO(DOCTYPESystemIdentifierSingleQuotedState);
- } else if (cc == '>') {
+ m_token.setSystemIdentifierToEmptyString();
+ ADVANCE_PAST_NON_NEWLINE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
+ }
+ if (character == '\'') {
parseError();
- m_token->setForceQuirks();
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- } else if (cc == kEndOfFileMarker) {
+ m_token.setSystemIdentifierToEmptyString();
+ ADVANCE_PAST_NON_NEWLINE_TO(DOCTYPESystemIdentifierSingleQuotedState);
+ }
+ if (character == '>') {
parseError();
- m_token->setForceQuirks();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
+ m_token.setForceQuirks();
+ return emitAndResumeInDataState(source);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- m_token->setForceQuirks();
- HTML_ADVANCE_TO(BogusDOCTYPEState);
+ m_token.setForceQuirks();
+ return emitAndReconsumeInDataState();
}
- }
+ parseError();
+ m_token.setForceQuirks();
+ ADVANCE_PAST_NON_NEWLINE_TO(BogusDOCTYPEState);
END_STATE()
- HTML_BEGIN_STATE(BeforeDOCTYPESystemIdentifierState) {
- if (isTokenizerWhitespace(cc))
- HTML_ADVANCE_TO(BeforeDOCTYPESystemIdentifierState);
- if (cc == '"') {
- m_token->setSystemIdentifierToEmptyString();
- HTML_ADVANCE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
- } else if (cc == '\'') {
- m_token->setSystemIdentifierToEmptyString();
- HTML_ADVANCE_TO(DOCTYPESystemIdentifierSingleQuotedState);
- } else if (cc == '>') {
- parseError();
- m_token->setForceQuirks();
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- } else if (cc == kEndOfFileMarker) {
+ BEGIN_STATE(BeforeDOCTYPESystemIdentifierState)
+ if (isTokenizerWhitespace(character))
+ ADVANCE_TO(BeforeDOCTYPESystemIdentifierState);
+ if (character == '"') {
+ m_token.setSystemIdentifierToEmptyString();
+ ADVANCE_PAST_NON_NEWLINE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
+ }
+ if (character == '\'') {
+ m_token.setSystemIdentifierToEmptyString();
+ ADVANCE_PAST_NON_NEWLINE_TO(DOCTYPESystemIdentifierSingleQuotedState);
+ }
+ if (character == '>') {
parseError();
- m_token->setForceQuirks();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
+ m_token.setForceQuirks();
+ return emitAndResumeInDataState(source);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- m_token->setForceQuirks();
- HTML_ADVANCE_TO(BogusDOCTYPEState);
+ m_token.setForceQuirks();
+ return emitAndReconsumeInDataState();
}
- }
+ parseError();
+ m_token.setForceQuirks();
+ ADVANCE_PAST_NON_NEWLINE_TO(BogusDOCTYPEState);
END_STATE()
- HTML_BEGIN_STATE(DOCTYPESystemIdentifierDoubleQuotedState) {
- if (cc == '"')
- HTML_ADVANCE_TO(AfterDOCTYPESystemIdentifierState);
- else if (cc == '>') {
+ BEGIN_STATE(DOCTYPESystemIdentifierDoubleQuotedState)
+ if (character == '"')
+ ADVANCE_PAST_NON_NEWLINE_TO(AfterDOCTYPESystemIdentifierState);
+ if (character == '>') {
parseError();
- m_token->setForceQuirks();
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- } else if (cc == kEndOfFileMarker) {
+ m_token.setForceQuirks();
+ return emitAndResumeInDataState(source);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- m_token->setForceQuirks();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
- m_token->appendToSystemIdentifier(cc);
- HTML_ADVANCE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
+ m_token.setForceQuirks();
+ return emitAndReconsumeInDataState();
}
- }
+ m_token.appendToSystemIdentifier(character);
+ ADVANCE_TO(DOCTYPESystemIdentifierDoubleQuotedState);
END_STATE()
- HTML_BEGIN_STATE(DOCTYPESystemIdentifierSingleQuotedState) {
- if (cc == '\'')
- HTML_ADVANCE_TO(AfterDOCTYPESystemIdentifierState);
- else if (cc == '>') {
+ BEGIN_STATE(DOCTYPESystemIdentifierSingleQuotedState)
+ if (character == '\'')
+ ADVANCE_PAST_NON_NEWLINE_TO(AfterDOCTYPESystemIdentifierState);
+ if (character == '>') {
parseError();
- m_token->setForceQuirks();
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- } else if (cc == kEndOfFileMarker) {
+ m_token.setForceQuirks();
+ return emitAndResumeInDataState(source);
+ }
+ if (character == kEndOfFileMarker) {
parseError();
- m_token->setForceQuirks();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
- m_token->appendToSystemIdentifier(cc);
- HTML_ADVANCE_TO(DOCTYPESystemIdentifierSingleQuotedState);
+ m_token.setForceQuirks();
+ return emitAndReconsumeInDataState();
}
- }
+ m_token.appendToSystemIdentifier(character);
+ ADVANCE_TO(DOCTYPESystemIdentifierSingleQuotedState);
END_STATE()
- HTML_BEGIN_STATE(AfterDOCTYPESystemIdentifierState) {
- if (isTokenizerWhitespace(cc))
- HTML_ADVANCE_TO(AfterDOCTYPESystemIdentifierState);
- else if (cc == '>')
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- else if (cc == kEndOfFileMarker) {
+ BEGIN_STATE(AfterDOCTYPESystemIdentifierState)
+ if (isTokenizerWhitespace(character))
+ ADVANCE_TO(AfterDOCTYPESystemIdentifierState);
+ if (character == '>')
+ return emitAndResumeInDataState(source);
+ if (character == kEndOfFileMarker) {
parseError();
- m_token->setForceQuirks();
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- } else {
- parseError();
- HTML_ADVANCE_TO(BogusDOCTYPEState);
+ m_token.setForceQuirks();
+ return emitAndReconsumeInDataState();
}
- }
+ parseError();
+ ADVANCE_PAST_NON_NEWLINE_TO(BogusDOCTYPEState);
END_STATE()
- HTML_BEGIN_STATE(BogusDOCTYPEState) {
- if (cc == '>')
- return emitAndResumeIn(source, HTMLTokenizer::DataState);
- else if (cc == kEndOfFileMarker)
- return emitAndReconsumeIn(source, HTMLTokenizer::DataState);
- HTML_ADVANCE_TO(BogusDOCTYPEState);
- }
+ BEGIN_STATE(BogusDOCTYPEState)
+ if (character == '>')
+ return emitAndResumeInDataState(source);
+ if (character == kEndOfFileMarker)
+ return emitAndReconsumeInDataState();
+ ADVANCE_TO(BogusDOCTYPEState);
END_STATE()
- HTML_BEGIN_STATE(CDATASectionState) {
- if (cc == ']')
- HTML_ADVANCE_TO(CDATASectionRightSquareBracketState);
- else if (cc == kEndOfFileMarker)
- HTML_RECONSUME_IN(DataState);
- else {
- bufferCharacter(cc);
- HTML_ADVANCE_TO(CDATASectionState);
- }
- }
+ BEGIN_STATE(CDATASectionState)
+ if (character == ']')
+ ADVANCE_PAST_NON_NEWLINE_TO(CDATASectionRightSquareBracketState);
+ if (character == kEndOfFileMarker)
+ RECONSUME_IN(DataState);
+ bufferCharacter(character);
+ ADVANCE_TO(CDATASectionState);
END_STATE()
- HTML_BEGIN_STATE(CDATASectionRightSquareBracketState) {
- if (cc == ']')
- HTML_ADVANCE_TO(CDATASectionDoubleRightSquareBracketState);
- else {
- bufferCharacter(']');
- HTML_RECONSUME_IN(CDATASectionState);
- }
- }
+ BEGIN_STATE(CDATASectionRightSquareBracketState)
+ if (character == ']')
+ ADVANCE_PAST_NON_NEWLINE_TO(CDATASectionDoubleRightSquareBracketState);
+ bufferASCIICharacter(']');
+ RECONSUME_IN(CDATASectionState);
+ END_STATE()
- HTML_BEGIN_STATE(CDATASectionDoubleRightSquareBracketState) {
- if (cc == '>')
- HTML_ADVANCE_TO(DataState);
- else {
- bufferCharacter(']');
- bufferCharacter(']');
- HTML_RECONSUME_IN(CDATASectionState);
- }
- }
+ BEGIN_STATE(CDATASectionDoubleRightSquareBracketState)
+ if (character == '>')
+ ADVANCE_PAST_NON_NEWLINE_TO(DataState);
+ bufferASCIICharacter(']');
+ bufferASCIICharacter(']');
+ RECONSUME_IN(CDATASectionState);
END_STATE()
}
@@ -1579,39 +1409,45 @@ String HTMLTokenizer::bufferedCharacters() const
void HTMLTokenizer::updateStateFor(const AtomicString& tagName)
{
if (tagName == textareaTag || tagName == titleTag)
- setState(HTMLTokenizer::RCDATAState);
+ m_state = RCDATAState;
else if (tagName == plaintextTag)
- setState(HTMLTokenizer::PLAINTEXTState);
+ m_state = PLAINTEXTState;
else if (tagName == scriptTag)
- setState(HTMLTokenizer::ScriptDataState);
+ m_state = ScriptDataState;
else if (tagName == styleTag
|| tagName == iframeTag
|| tagName == xmpTag
|| (tagName == noembedTag && m_options.pluginsEnabled)
|| tagName == noframesTag
|| (tagName == noscriptTag && m_options.scriptEnabled))
- setState(HTMLTokenizer::RAWTEXTState);
+ m_state = RAWTEXTState;
+}
+
+inline void HTMLTokenizer::appendToTemporaryBuffer(UChar character)
+{
+ ASSERT(isASCII(character));
+ m_temporaryBuffer.append(character);
}
-inline bool HTMLTokenizer::temporaryBufferIs(const String& expectedString)
+inline bool HTMLTokenizer::temporaryBufferIs(const char* expectedString)
{
return vectorEqualsString(m_temporaryBuffer, expectedString);
}
-inline void HTMLTokenizer::addToPossibleEndTag(LChar cc)
+inline void HTMLTokenizer::appendToPossibleEndTag(UChar character)
{
- ASSERT(isEndTagBufferingState(m_state));
- m_bufferedEndTagName.append(cc);
+ ASSERT(isASCII(character));
+ m_bufferedEndTagName.append(character);
}
-inline bool HTMLTokenizer::isAppropriateEndTag()
+inline bool HTMLTokenizer::isAppropriateEndTag() const
{
if (m_bufferedEndTagName.size() != m_appropriateEndTagName.size())
return false;
- size_t numCharacters = m_bufferedEndTagName.size();
+ unsigned size = m_bufferedEndTagName.size();
- for (size_t i = 0; i < numCharacters; i++) {
+ for (unsigned i = 0; i < size; i++) {
if (m_bufferedEndTagName[i] != m_appropriateEndTagName[i])
return false;
}
@@ -1621,7 +1457,6 @@ inline bool HTMLTokenizer::isAppropriateEndTag()
inline void HTMLTokenizer::parseError()
{
- notImplemented();
}
}
diff --git a/Source/WebCore/html/parser/HTMLTokenizer.h b/Source/WebCore/html/parser/HTMLTokenizer.h
index 38021e87d..a553acbd9 100644
--- a/Source/WebCore/html/parser/HTMLTokenizer.h
+++ b/Source/WebCore/html/parser/HTMLTokenizer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2015 Apple Inc. All Rights Reserved.
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,25 +24,62 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLTokenizer_h
-#define HTMLTokenizer_h
+#pragma once
#include "HTMLParserOptions.h"
#include "HTMLToken.h"
#include "InputStreamPreprocessor.h"
-#include "SegmentedString.h"
namespace WebCore {
+class SegmentedString;
+
class HTMLTokenizer {
- WTF_MAKE_NONCOPYABLE(HTMLTokenizer);
- WTF_MAKE_FAST_ALLOCATED;
public:
- explicit HTMLTokenizer(const HTMLParserOptions&);
- ~HTMLTokenizer();
+ explicit HTMLTokenizer(const HTMLParserOptions& = HTMLParserOptions());
+
+ // If we can't parse a whole token, this returns null.
+ class TokenPtr;
+ TokenPtr nextToken(SegmentedString&);
+
+ // Used by HTMLSourceTracker.
+ void setTokenAttributeBaseOffset(unsigned);
+
+ // Returns a copy of any characters buffered internally by the tokenizer.
+ // The tokenizer buffers characters when searching for the </script> token that terminates a script element.
+ String bufferedCharacters() const;
+ size_t numberOfBufferedCharacters() const;
+
+ // Updates the tokenizer's state according to the given tag name. This is an approximation of how the tree
+ // builder would update the tokenizer's state. This method is useful for approximating HTML tokenization.
+ // To get exactly the correct tokenization, you need the real tree builder.
+ //
+ // The main failures in the approximation are as follows:
+ //
+ // * The first set of character tokens emitted for a <pre> element might contain an extra leading newline.
+ // * The replacement of U+0000 with U+FFFD will not be sensitive to the tree builder's insertion mode.
+ // * CDATA sections in foreign content will be tokenized as bogus comments instead of as character tokens.
+ //
+ // This approximation is also the algorithm called for when parsing an HTML fragment.
+ // https://html.spec.whatwg.org/multipage/syntax.html#parsing-html-fragments
+ void updateStateFor(const AtomicString& tagName);
+
+ void setForceNullCharacterReplacement(bool);
+
+ bool shouldAllowCDATA() const;
+ void setShouldAllowCDATA(bool);
- void reset();
+ bool isInDataState() const;
+ void setDataState();
+ void setPLAINTEXTState();
+ void setRAWTEXTState();
+ void setRCDATAState();
+ void setScriptDataState();
+
+ bool neverSkipNullCharacters() const;
+
+private:
enum State {
DataState,
CharacterReferenceInDataState,
@@ -88,10 +125,7 @@ public:
AfterAttributeValueQuotedState,
SelfClosingStartTagState,
BogusCommentState,
- // The ContinueBogusCommentState is not in the HTML5 spec, but we use
- // it internally to keep track of whether we've started the bogus
- // comment token yet.
- ContinueBogusCommentState,
+ ContinueBogusCommentState, // Not in the HTML spec, used internally to track whether we started the bogus comment token.
MarkupDeclarationOpenState,
CommentStartState,
CommentStartDashState,
@@ -121,148 +155,201 @@ public:
CDATASectionDoubleRightSquareBracketState,
};
- // This function returns true if it emits a token. Otherwise, callers
- // must provide the same (in progress) token on the next call (unless
- // they call reset() first).
- bool nextToken(SegmentedString&, HTMLToken&);
+ bool processToken(SegmentedString&);
+ bool processEntity(SegmentedString&);
- // Returns a copy of any characters buffered internally by the tokenizer.
- // The tokenizer buffers characters when searching for the </script> token
- // that terminates a script element.
- String bufferedCharacters() const;
+ void parseError();
- size_t numberOfBufferedCharacters() const
- {
- // Notice that we add 2 to the length of the m_temporaryBuffer to
- // account for the "</" characters, which are effecitvely buffered in
- // the tokenizer's state machine.
- return m_temporaryBuffer.size() ? m_temporaryBuffer.size() + 2 : 0;
- }
+ void bufferASCIICharacter(UChar);
+ void bufferCharacter(UChar);
- // Updates the tokenizer's state according to the given tag name. This is
- // an approximation of how the tree builder would update the tokenizer's
- // state. This method is useful for approximating HTML tokenization. To
- // get exactly the correct tokenization, you need the real tree builder.
- //
- // The main failures in the approximation are as follows:
- //
- // * The first set of character tokens emitted for a <pre> element might
- // contain an extra leading newline.
- // * The replacement of U+0000 with U+FFFD will not be sensitive to the
- // tree builder's insertion mode.
- // * CDATA sections in foreign content will be tokenized as bogus comments
- // instead of as character tokens.
- //
- void updateStateFor(const AtomicString& tagName);
+ bool emitAndResumeInDataState(SegmentedString&);
+ bool emitAndReconsumeInDataState();
+ bool emitEndOfFile(SegmentedString&);
- bool forceNullCharacterReplacement() const { return m_forceNullCharacterReplacement; }
- void setForceNullCharacterReplacement(bool value) { m_forceNullCharacterReplacement = value; }
+ // Return true if we wil emit a character token before dealing with the buffered end tag.
+ void flushBufferedEndTag();
+ bool commitToPartialEndTag(SegmentedString&, UChar, State);
+ bool commitToCompleteEndTag(SegmentedString&);
- bool shouldAllowCDATA() const { return m_shouldAllowCDATA; }
- void setShouldAllowCDATA(bool value) { m_shouldAllowCDATA = value; }
+ void appendToTemporaryBuffer(UChar);
+ bool temporaryBufferIs(const char*);
- State state() const { return m_state; }
- void setState(State state) { m_state = state; }
+ // Sometimes we speculatively consume input characters and we don't know whether they represent
+ // end tags or RCDATA, etc. These functions help manage these state.
+ bool inEndTagBufferingState() const;
+ void appendToPossibleEndTag(UChar);
+ void saveEndTagNameIfNeeded();
+ bool isAppropriateEndTag() const;
- inline bool shouldSkipNullCharacters() const
- {
- return !m_forceNullCharacterReplacement
- && (m_state == HTMLTokenizer::DataState
- || m_state == HTMLTokenizer::RCDATAState
- || m_state == HTMLTokenizer::RAWTEXTState);
- }
+ bool haveBufferedCharacterToken() const;
+
+ static bool isNullCharacterSkippingState(State);
+
+ State m_state { DataState };
+ bool m_forceNullCharacterReplacement { false };
+ bool m_shouldAllowCDATA { false };
+
+ mutable HTMLToken m_token;
+
+ // https://html.spec.whatwg.org/#additional-allowed-character
+ UChar m_additionalAllowedCharacter { 0 };
+
+ // https://html.spec.whatwg.org/#preprocessing-the-input-stream
+ InputStreamPreprocessor<HTMLTokenizer> m_preprocessor;
+
+ Vector<UChar, 32> m_appropriateEndTagName;
+
+ // https://html.spec.whatwg.org/#temporary-buffer
+ Vector<LChar, 32> m_temporaryBuffer;
+
+ // We occasionally want to emit both a character token and an end tag
+ // token (e.g., when lexing script). We buffer the name of the end tag
+ // token here so we remember it next time we re-enter the tokenizer.
+ Vector<LChar, 32> m_bufferedEndTagName;
+
+ const HTMLParserOptions m_options;
+};
+
+class HTMLTokenizer::TokenPtr {
+public:
+ TokenPtr();
+ ~TokenPtr();
+
+ TokenPtr(TokenPtr&&);
+ TokenPtr& operator=(TokenPtr&&) = delete;
+
+ void clear();
+
+ operator bool() const;
+
+ HTMLToken& operator*() const;
+ HTMLToken* operator->() const;
private:
- inline bool processEntity(SegmentedString&);
+ friend class HTMLTokenizer;
+ explicit TokenPtr(HTMLToken*);
- inline void parseError();
+ HTMLToken* m_token { nullptr };
+};
- inline void bufferCharacter(UChar character)
- {
- ASSERT(character != kEndOfFileMarker);
- m_token->ensureIsCharacterToken();
- m_token->appendToCharacter(character);
- }
+inline HTMLTokenizer::TokenPtr::TokenPtr()
+{
+}
- inline bool emitAndResumeIn(SegmentedString& source, State state)
- {
- saveEndTagNameIfNeeded();
- m_state = state;
- source.advanceAndUpdateLineNumber();
- return true;
- }
-
- inline bool emitAndReconsumeIn(SegmentedString&, State state)
- {
- saveEndTagNameIfNeeded();
- m_state = state;
- return true;
- }
+inline HTMLTokenizer::TokenPtr::TokenPtr(HTMLToken* token)
+ : m_token(token)
+{
+}
- inline bool emitEndOfFile(SegmentedString& source)
- {
- if (haveBufferedCharacterToken())
- return true;
- m_state = HTMLTokenizer::DataState;
- source.advanceAndUpdateLineNumber();
+inline HTMLTokenizer::TokenPtr::~TokenPtr()
+{
+ if (m_token)
m_token->clear();
- m_token->makeEndOfFile();
- return true;
+}
+
+inline HTMLTokenizer::TokenPtr::TokenPtr(TokenPtr&& other)
+ : m_token(other.m_token)
+{
+ other.m_token = nullptr;
+}
+
+inline void HTMLTokenizer::TokenPtr::clear()
+{
+ if (m_token) {
+ m_token->clear();
+ m_token = nullptr;
}
+}
- inline bool flushEmitAndResumeIn(SegmentedString&, State);
+inline HTMLTokenizer::TokenPtr::operator bool() const
+{
+ return m_token;
+}
- // Return whether we need to emit a character token before dealing with
- // the buffered end tag.
- inline bool flushBufferedEndTag(SegmentedString&);
- inline bool temporaryBufferIs(const String&);
+inline HTMLToken& HTMLTokenizer::TokenPtr::operator*() const
+{
+ ASSERT(m_token);
+ return *m_token;
+}
- // Sometimes we speculatively consume input characters and we don't
- // know whether they represent end tags or RCDATA, etc. These
- // functions help manage these state.
- inline void addToPossibleEndTag(LChar cc);
+inline HTMLToken* HTMLTokenizer::TokenPtr::operator->() const
+{
+ ASSERT(m_token);
+ return m_token;
+}
- inline void saveEndTagNameIfNeeded()
- {
- ASSERT(m_token->type() != HTMLToken::Uninitialized);
- if (m_token->type() == HTMLToken::StartTag)
- m_appropriateEndTagName = m_token->name();
- }
- inline bool isAppropriateEndTag();
+inline HTMLTokenizer::TokenPtr HTMLTokenizer::nextToken(SegmentedString& source)
+{
+ return TokenPtr(processToken(source) ? &m_token : nullptr);
+}
+inline void HTMLTokenizer::setTokenAttributeBaseOffset(unsigned offset)
+{
+ m_token.setAttributeBaseOffset(offset);
+}
- inline bool haveBufferedCharacterToken()
- {
- return m_token->type() == HTMLToken::Character;
- }
+inline size_t HTMLTokenizer::numberOfBufferedCharacters() const
+{
+ // Notice that we add 2 to the length of the m_temporaryBuffer to
+ // account for the "</" characters, which are effecitvely buffered in
+ // the tokenizer's state machine.
+ return m_temporaryBuffer.size() ? m_temporaryBuffer.size() + 2 : 0;
+}
- State m_state;
- bool m_forceNullCharacterReplacement;
- bool m_shouldAllowCDATA;
+inline void HTMLTokenizer::setForceNullCharacterReplacement(bool value)
+{
+ m_forceNullCharacterReplacement = value;
+}
- // m_token is owned by the caller. If nextToken is not on the stack,
- // this member might be pointing to unallocated memory.
- HTMLToken* m_token;
+inline bool HTMLTokenizer::shouldAllowCDATA() const
+{
+ return m_shouldAllowCDATA;
+}
- // http://www.whatwg.org/specs/web-apps/current-work/#additional-allowed-character
- UChar m_additionalAllowedCharacter;
+inline void HTMLTokenizer::setShouldAllowCDATA(bool value)
+{
+ m_shouldAllowCDATA = value;
+}
- // http://www.whatwg.org/specs/web-apps/current-work/#preprocessing-the-input-stream
- InputStreamPreprocessor<HTMLTokenizer> m_inputStreamPreprocessor;
+inline bool HTMLTokenizer::isInDataState() const
+{
+ return m_state == DataState;
+}
- Vector<UChar, 32> m_appropriateEndTagName;
+inline void HTMLTokenizer::setDataState()
+{
+ m_state = DataState;
+}
- // http://www.whatwg.org/specs/web-apps/current-work/#temporary-buffer
- Vector<LChar, 32> m_temporaryBuffer;
+inline void HTMLTokenizer::setPLAINTEXTState()
+{
+ m_state = PLAINTEXTState;
+}
- // We occationally want to emit both a character token and an end tag
- // token (e.g., when lexing script). We buffer the name of the end tag
- // token here so we remember it next time we re-enter the tokenizer.
- Vector<LChar, 32> m_bufferedEndTagName;
+inline void HTMLTokenizer::setRAWTEXTState()
+{
+ m_state = RAWTEXTState;
+}
- HTMLParserOptions m_options;
-};
+inline void HTMLTokenizer::setRCDATAState()
+{
+ m_state = RCDATAState;
+}
+
+inline void HTMLTokenizer::setScriptDataState()
+{
+ m_state = ScriptDataState;
+}
+
+inline bool HTMLTokenizer::isNullCharacterSkippingState(State state)
+{
+ return state == DataState || state == RCDATAState || state == RAWTEXTState;
+}
+inline bool HTMLTokenizer::neverSkipNullCharacters() const
+{
+ return m_forceNullCharacterReplacement;
}
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLTreeBuilder.cpp b/Source/WebCore/html/parser/HTMLTreeBuilder.cpp
index 46b3baf47..4b22f4f8f 100644
--- a/Source/WebCore/html/parser/HTMLTreeBuilder.cpp
+++ b/Source/WebCore/html/parser/HTMLTreeBuilder.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,48 +30,42 @@
#include "DocumentFragment.h"
#include "HTMLDocument.h"
#include "HTMLDocumentParser.h"
+#include "HTMLFormControlElement.h"
#include "HTMLFormElement.h"
#include "HTMLOptGroupElement.h"
#include "HTMLOptionElement.h"
#include "HTMLParserIdioms.h"
+#include "HTMLScriptElement.h"
#include "HTMLTableElement.h"
-#include "HTMLTemplateElement.h"
+#include "JSCustomElementInterface.h"
#include "LocalizedStrings.h"
#include "NotImplemented.h"
+#include "SVGScriptElement.h"
#include "XLinkNames.h"
#include "XMLNSNames.h"
#include "XMLNames.h"
-#include <wtf/MainThread.h>
+#include <wtf/NeverDestroyed.h>
#include <wtf/unicode/CharacterNames.h>
-// FIXME: Extract the following iOS-specific code into a separate file.
-#if PLATFORM(IOS)
-#include "SoftLinking.h"
-
-#ifdef __has_include
-#if __has_include(<DataDetectorsCore/DDDFACache.h>)
-#include <DataDetectorsCore/DDDFACache.h>
-#else
-typedef void* DDDFACacheRef;
-#endif
-
-#if __has_include(<DataDetectorsCore/DDDFAScanner.h>)
-#include <DataDetectorsCore/DDDFAScanner.h>
-#else
-typedef void* DDDFAScannerRef;
-#endif
-#endif
-
-SOFT_LINK_PRIVATE_FRAMEWORK_OPTIONAL(DataDetectorsCore)
-SOFT_LINK(DataDetectorsCore, DDDFACacheCreateFromFramework, DDDFACacheRef, (), ())
-SOFT_LINK(DataDetectorsCore, DDDFAScannerCreateFromCache, DDDFAScannerRef, (DDDFACacheRef cache), (cache))
-SOFT_LINK(DataDetectorsCore, DDDFAScannerFirstResultInUnicharArray, Boolean, (DDDFAScannerRef scanner, const UniChar* str, unsigned length, int* startPos, int* endPos), (scanner, str, length, startPos, endPos))
+#if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS)
+#include "TelephoneNumberDetector.h"
#endif
namespace WebCore {
using namespace HTMLNames;
+CustomElementConstructionData::CustomElementConstructionData(Ref<JSCustomElementInterface>&& customElementInterface, const AtomicString& name, Vector<Attribute>&& attributes)
+ : elementInterface(WTFMove(customElementInterface))
+ , name(name)
+ , attributes(WTFMove(attributes))
+{
+}
+
+CustomElementConstructionData::~CustomElementConstructionData()
+{
+}
+
namespace {
inline bool isHTMLSpaceOrReplacementCharacter(UChar character)
@@ -81,9 +75,9 @@ inline bool isHTMLSpaceOrReplacementCharacter(UChar character)
}
-static TextPosition uninitializedPositionValue1()
+static inline TextPosition uninitializedPositionValue1()
{
- return TextPosition(OrdinalNumber::fromOneBasedInt(-1), OrdinalNumber::first());
+ return TextPosition(OrdinalNumber::fromOneBasedInt(-1), OrdinalNumber());
}
static inline bool isAllWhitespace(const String& string)
@@ -108,9 +102,7 @@ static bool isNumberedHeaderTag(const AtomicString& tagName)
static bool isCaptionColOrColgroupTag(const AtomicString& tagName)
{
- return tagName == captionTag
- || tagName == colTag
- || tagName == colgroupTag;
+ return tagName == captionTag || tagName == colTag || tagName == colgroupTag;
}
static bool isTableCellContextTag(const AtomicString& tagName)
@@ -120,9 +112,7 @@ static bool isTableCellContextTag(const AtomicString& tagName)
static bool isTableBodyContextTag(const AtomicString& tagName)
{
- return tagName == tbodyTag
- || tagName == tfootTag
- || tagName == theadTag;
+ return tagName == tbodyTag || tagName == tfootTag || tagName == theadTag;
}
static bool isNonAnchorNonNobrFormattingTag(const AtomicString& tagName)
@@ -143,31 +133,27 @@ static bool isNonAnchorNonNobrFormattingTag(const AtomicString& tagName)
static bool isNonAnchorFormattingTag(const AtomicString& tagName)
{
- return tagName == nobrTag
- || isNonAnchorNonNobrFormattingTag(tagName);
+ return tagName == nobrTag || isNonAnchorNonNobrFormattingTag(tagName);
}
-// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#formatting
-static bool isFormattingTag(const AtomicString& tagName)
+// https://html.spec.whatwg.org/multipage/syntax.html#formatting
+bool HTMLConstructionSite::isFormattingTag(const AtomicString& tagName)
{
return tagName == aTag || isNonAnchorFormattingTag(tagName);
}
class HTMLTreeBuilder::ExternalCharacterTokenBuffer {
- WTF_MAKE_NONCOPYABLE(ExternalCharacterTokenBuffer);
public:
- explicit ExternalCharacterTokenBuffer(AtomicHTMLToken* token)
- : m_current(token->characters())
- , m_end(m_current + token->charactersLength())
- , m_isAll8BitData(token->isAll8BitData())
+ explicit ExternalCharacterTokenBuffer(AtomicHTMLToken& token)
+ : m_text(token.characters(), token.charactersLength())
+ , m_isAll8BitData(token.charactersIsAll8BitData())
{
ASSERT(!isEmpty());
}
explicit ExternalCharacterTokenBuffer(const String& string)
- : m_current(string.deprecatedCharacters())
- , m_end(m_current + string.length())
- , m_isAll8BitData(string.length() && string.is8Bit())
+ : m_text(string)
+ , m_isAll8BitData(m_text.is8Bit())
{
ASSERT(!isEmpty());
}
@@ -177,15 +163,15 @@ public:
ASSERT(isEmpty());
}
- bool isEmpty() const { return m_current == m_end; }
+ bool isEmpty() const { return m_text.isEmpty(); }
bool isAll8BitData() const { return m_isAll8BitData; }
void skipAtMostOneLeadingNewline()
{
ASSERT(!isEmpty());
- if (*m_current == '\n')
- ++m_current;
+ if (m_text[0] == '\n')
+ m_text = m_text.substring(1);
}
void skipLeadingWhitespace()
@@ -205,246 +191,240 @@ public:
String takeRemaining()
{
- ASSERT(!isEmpty());
- const UChar* start = m_current;
- m_current = m_end;
- size_t length = m_current - start;
-
- if (isAll8BitData())
- return String::make8BitFrom16BitSource(start, length);
-
- return String(start, length);
+ String result = makeString(m_text);
+ m_text = StringView();
+ return result;
}
void giveRemainingTo(StringBuilder& recipient)
{
- recipient.append(m_current, m_end - m_current);
- m_current = m_end;
+ recipient.append(m_text);
+ m_text = StringView();
}
String takeRemainingWhitespace()
{
ASSERT(!isEmpty());
- Vector<UChar> whitespace;
+ Vector<LChar, 8> whitespace;
do {
- UChar cc = *m_current++;
- if (isHTMLSpace(cc))
- whitespace.append(cc);
- } while (m_current < m_end);
+ UChar character = m_text[0];
+ if (isHTMLSpace(character))
+ whitespace.append(character);
+ m_text = m_text.substring(1);
+ } while (!m_text.isEmpty());
+
// Returning the null string when there aren't any whitespace
// characters is slightly cleaner semantically because we don't want
// to insert a text node (as opposed to inserting an empty text node).
if (whitespace.isEmpty())
return String();
- return String::adopt(whitespace);
+
+ return String::adopt(WTFMove(whitespace));
}
private:
- template<bool characterPredicate(UChar)>
- void skipLeading()
+ template<bool characterPredicate(UChar)> void skipLeading()
{
ASSERT(!isEmpty());
- while (characterPredicate(*m_current)) {
- if (++m_current == m_end)
+ while (characterPredicate(m_text[0])) {
+ m_text = m_text.substring(1);
+ if (m_text.isEmpty())
return;
}
}
- template<bool characterPredicate(UChar)>
- String takeLeading()
+ template<bool characterPredicate(UChar)> String takeLeading()
{
ASSERT(!isEmpty());
- const UChar* start = m_current;
+ StringView start = m_text;
skipLeading<characterPredicate>();
- if (start == m_current)
+ if (start.length() == m_text.length())
return String();
- if (isAll8BitData())
- return String::make8BitFrom16BitSource(start, m_current - start);
- return String(start, m_current - start);
+ return makeString(start.substring(0, start.length() - m_text.length()));
}
- const UChar* m_current;
- const UChar* m_end;
+ String makeString(StringView stringView) const
+ {
+ if (stringView.is8Bit() || !isAll8BitData())
+ return stringView.toString();
+ return String::make8BitFrom16BitSource(stringView.characters16(), stringView.length());
+ }
+
+ StringView m_text;
bool m_isAll8BitData;
};
+inline bool HTMLTreeBuilder::isParsingTemplateContents() const
+{
+ return m_tree.openElements().hasTemplateInHTMLScope();
+}
+
+inline bool HTMLTreeBuilder::isParsingFragmentOrTemplateContents() const
+{
+ return isParsingFragment() || isParsingTemplateContents();
+}
HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser& parser, HTMLDocument& document, ParserContentPolicy parserContentPolicy, const HTMLParserOptions& options)
- : m_framesetOk(true)
-#ifndef NDEBUG
- , m_isAttached(true)
-#endif
+ : m_parser(parser)
+ , m_options(options)
, m_tree(document, parserContentPolicy, options.maximumDOMTreeDepth)
- , m_insertionMode(InsertionMode::Initial)
- , m_originalInsertionMode(InsertionMode::Initial)
- , m_shouldSkipLeadingNewline(false)
- , m_parser(parser)
, m_scriptToProcessStartPosition(uninitializedPositionValue1())
- , m_options(options)
{
+#if !ASSERT_DISABLED
+ m_destructionProhibited = false;
+#endif
}
-// FIXME: Member variables should be grouped into self-initializing structs to
-// minimize code duplication between these constructors.
-HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser& parser, DocumentFragment& fragment, Element* contextElement, ParserContentPolicy parserContentPolicy, const HTMLParserOptions& options)
- : m_framesetOk(true)
-#ifndef NDEBUG
- , m_isAttached(true)
-#endif
+HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser& parser, DocumentFragment& fragment, Element& contextElement, ParserContentPolicy parserContentPolicy, const HTMLParserOptions& options)
+ : m_parser(parser)
+ , m_options(options)
, m_fragmentContext(fragment, contextElement)
, m_tree(fragment, parserContentPolicy, options.maximumDOMTreeDepth)
- , m_insertionMode(InsertionMode::Initial)
- , m_originalInsertionMode(InsertionMode::Initial)
- , m_shouldSkipLeadingNewline(false)
- , m_parser(parser)
, m_scriptToProcessStartPosition(uninitializedPositionValue1())
- , m_options(options)
{
ASSERT(isMainThread());
- // FIXME: This assertion will become invalid if <http://webkit.org/b/60316> is fixed.
- ASSERT(contextElement);
- if (contextElement) {
- // Steps 4.2-4.6 of the HTML5 Fragment Case parsing algorithm:
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#fragment-case
- // For efficiency, we skip step 4.2 ("Let root be a new html element with no attributes")
- // and instead use the DocumentFragment as a root node.
- m_tree.openElements()->pushRootNode(HTMLStackItem::create(&fragment, HTMLStackItem::ItemForDocumentFragmentNode));
-
-#if ENABLE(TEMPLATE_ELEMENT)
- if (contextElement->hasTagName(templateTag))
- m_templateInsertionModes.append(InsertionMode::TemplateContents);
-#endif
- resetInsertionModeAppropriately();
- m_tree.setForm(!contextElement || isHTMLFormElement(contextElement) ? toHTMLFormElement(contextElement) : HTMLFormElement::findClosestFormAncestor(*contextElement));
- }
-}
+ // https://html.spec.whatwg.org/multipage/syntax.html#parsing-html-fragments
+ // For efficiency, we skip step 5 ("Let root be a new html element with no attributes") and instead use the DocumentFragment as a root node.
+ m_tree.openElements().pushRootNode(HTMLStackItem::create(fragment));
-HTMLTreeBuilder::~HTMLTreeBuilder()
-{
-}
+ if (contextElement.hasTagName(templateTag))
+ m_templateInsertionModes.append(InsertionMode::TemplateContents);
-void HTMLTreeBuilder::detach()
-{
-#ifndef NDEBUG
- // This call makes little sense in fragment mode, but for consistency
- // DocumentParser expects detach() to always be called before it's destroyed.
- m_isAttached = false;
+ resetInsertionModeAppropriately();
+
+ m_tree.setForm(is<HTMLFormElement>(contextElement) ? &downcast<HTMLFormElement>(contextElement) : HTMLFormElement::findClosestFormAncestor(contextElement));
+
+#if !ASSERT_DISABLED
+ m_destructionProhibited = false;
#endif
- // HTMLConstructionSite might be on the callstack when detach() is called
- // otherwise we'd just call m_tree.clear() here instead.
- m_tree.detach();
}
HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext()
- : m_fragment(0)
- , m_contextElement(0)
{
}
-HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext(DocumentFragment& fragment, Element* contextElement)
+HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext(DocumentFragment& fragment, Element& contextElement)
: m_fragment(&fragment)
- , m_contextElement(contextElement)
{
ASSERT(!fragment.hasChildNodes());
+ m_contextElementStackItem = HTMLStackItem::create(contextElement);
+}
+
+inline Element& HTMLTreeBuilder::FragmentParsingContext::contextElement() const
+{
+ return contextElementStackItem().element();
}
-HTMLTreeBuilder::FragmentParsingContext::~FragmentParsingContext()
+inline HTMLStackItem& HTMLTreeBuilder::FragmentParsingContext::contextElementStackItem() const
{
+ ASSERT(m_fragment);
+ return *m_contextElementStackItem;
}
-PassRefPtr<Element> HTMLTreeBuilder::takeScriptToProcess(TextPosition& scriptStartPosition)
+RefPtr<ScriptElement> HTMLTreeBuilder::takeScriptToProcess(TextPosition& scriptStartPosition)
{
- ASSERT(m_scriptToProcess);
+ ASSERT(!m_destroyed);
+
+ if (!m_scriptToProcess)
+ return nullptr;
+
// Unpause ourselves, callers may pause us again when processing the script.
- // The HTML5 spec is written as though scripts are executed inside the tree
- // builder. We pause the parser to exit the tree builder, and then resume
- // before running scripts.
+ // The HTML5 spec is written as though scripts are executed inside the tree builder.
+ // We pause the parser to exit the tree builder, and then resume before running scripts.
scriptStartPosition = m_scriptToProcessStartPosition;
m_scriptToProcessStartPosition = uninitializedPositionValue1();
- return m_scriptToProcess.release();
+ return WTFMove(m_scriptToProcess);
}
-void HTMLTreeBuilder::constructTree(AtomicHTMLToken* token)
+void HTMLTreeBuilder::constructTree(AtomicHTMLToken&& token)
{
+#if !ASSERT_DISABLED
+ ASSERT(!m_destroyed);
+ ASSERT(!m_destructionProhibited);
+ m_destructionProhibited = true;
+#endif
+
if (shouldProcessTokenInForeignContent(token))
- processTokenInForeignContent(token);
+ processTokenInForeignContent(WTFMove(token));
else
- processToken(token);
+ processToken(WTFMove(token));
- if (m_parser.tokenizer()) {
- bool inForeignContent = !m_tree.isEmpty()
- && !m_tree.currentStackItem()->isInHTMLNamespace()
- && !HTMLElementStack::isHTMLIntegrationPoint(m_tree.currentStackItem())
- && !HTMLElementStack::isMathMLTextIntegrationPoint(m_tree.currentStackItem());
+ bool inForeignContent = !m_tree.isEmpty()
+ && !isInHTMLNamespace(adjustedCurrentStackItem())
+ && !HTMLElementStack::isHTMLIntegrationPoint(m_tree.currentStackItem())
+ && !HTMLElementStack::isMathMLTextIntegrationPoint(m_tree.currentStackItem());
- m_parser.tokenizer()->setForceNullCharacterReplacement(m_insertionMode == InsertionMode::Text || inForeignContent);
- m_parser.tokenizer()->setShouldAllowCDATA(inForeignContent);
- }
+ m_parser.tokenizer().setForceNullCharacterReplacement(m_insertionMode == InsertionMode::Text || inForeignContent);
+ m_parser.tokenizer().setShouldAllowCDATA(inForeignContent);
+
+#if !ASSERT_DISABLED
+ m_destructionProhibited = false;
+#endif
m_tree.executeQueuedTasks();
- // We might be detached now.
+ // The tree builder might have been destroyed as an indirect result of executing the queued tasks.
}
-void HTMLTreeBuilder::processToken(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processToken(AtomicHTMLToken&& token)
{
- switch (token->type()) {
+ switch (token.type()) {
case HTMLToken::Uninitialized:
ASSERT_NOT_REACHED();
break;
case HTMLToken::DOCTYPE:
m_shouldSkipLeadingNewline = false;
- processDoctypeToken(token);
+ processDoctypeToken(WTFMove(token));
break;
case HTMLToken::StartTag:
m_shouldSkipLeadingNewline = false;
- processStartTag(token);
+ processStartTag(WTFMove(token));
break;
case HTMLToken::EndTag:
m_shouldSkipLeadingNewline = false;
- processEndTag(token);
+ processEndTag(WTFMove(token));
break;
case HTMLToken::Comment:
m_shouldSkipLeadingNewline = false;
- processComment(token);
+ processComment(WTFMove(token));
return;
case HTMLToken::Character:
- processCharacter(token);
+ processCharacter(WTFMove(token));
break;
case HTMLToken::EndOfFile:
m_shouldSkipLeadingNewline = false;
- processEndOfFile(token);
+ processEndOfFile(WTFMove(token));
break;
}
}
-void HTMLTreeBuilder::processDoctypeToken(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processDoctypeToken(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::DOCTYPE);
+ ASSERT(token.type() == HTMLToken::DOCTYPE);
if (m_insertionMode == InsertionMode::Initial) {
- m_tree.insertDoctype(token);
- setInsertionMode(InsertionMode::BeforeHTML);
+ m_tree.insertDoctype(WTFMove(token));
+ m_insertionMode = InsertionMode::BeforeHTML;
return;
}
if (m_insertionMode == InsertionMode::InTableText) {
defaultForInTableText();
- processDoctypeToken(token);
+ processDoctypeToken(WTFMove(token));
return;
}
parseError(token);
}
-void HTMLTreeBuilder::processFakeStartTag(const QualifiedName& tagName, const Vector<Attribute>& attributes)
+void HTMLTreeBuilder::processFakeStartTag(const QualifiedName& tagName, Vector<Attribute>&& attributes)
{
// FIXME: We'll need a fancier conversion than just "localName" for SVG/MathML tags.
- AtomicHTMLToken fakeToken(HTMLToken::StartTag, tagName.localName(), attributes);
- processStartTag(&fakeToken);
+ AtomicHTMLToken fakeToken(HTMLToken::StartTag, tagName.localName(), WTFMove(attributes));
+ processStartTag(WTFMove(fakeToken));
}
void HTMLTreeBuilder::processFakeEndTag(const AtomicString& tagName)
{
AtomicHTMLToken fakeToken(HTMLToken::EndTag, tagName);
- processEndTag(&fakeToken);
+ processEndTag(WTFMove(fakeToken));
}
void HTMLTreeBuilder::processFakeEndTag(const QualifiedName& tagName)
@@ -462,428 +442,363 @@ void HTMLTreeBuilder::processFakeCharacters(const String& characters)
void HTMLTreeBuilder::processFakePEndTagIfPInButtonScope()
{
- if (!m_tree.openElements()->inButtonScope(pTag.localName()))
+ if (!m_tree.openElements().inButtonScope(pTag.localName()))
return;
AtomicHTMLToken endP(HTMLToken::EndTag, pTag.localName());
- processEndTag(&endP);
-}
-
-Vector<Attribute> HTMLTreeBuilder::attributesForIsindexInput(AtomicHTMLToken* token)
-{
- Vector<Attribute> attributes = token->attributes();
- for (int i = attributes.size() - 1; i >= 0; --i) {
- const QualifiedName& name = attributes.at(i).name();
- if (name.matches(nameAttr) || name.matches(actionAttr) || name.matches(promptAttr))
- attributes.remove(i);
- }
-
- attributes.append(Attribute(nameAttr, isindexTag.localName()));
- return attributes;
-}
-
-void HTMLTreeBuilder::processIsindexStartTagForInBody(AtomicHTMLToken* token)
-{
- ASSERT(token->type() == HTMLToken::StartTag);
- ASSERT(token->name() == isindexTag);
- parseError(token);
- if (m_tree.form() && !isParsingTemplateContents())
- return;
- notImplemented(); // Acknowledge self-closing flag
- processFakeStartTag(formTag);
- Attribute* actionAttribute = token->getAttributeItem(actionAttr);
- if (actionAttribute)
- m_tree.form()->setAttribute(actionAttr, actionAttribute->value());
- processFakeStartTag(hrTag);
- processFakeStartTag(labelTag);
- Attribute* promptAttribute = token->getAttributeItem(promptAttr);
- if (promptAttribute)
- processFakeCharacters(promptAttribute->value());
- else
- processFakeCharacters(searchableIndexIntroduction());
- processFakeStartTag(inputTag, attributesForIsindexInput(token));
- notImplemented(); // This second set of characters may be needed by non-english locales.
- processFakeEndTag(labelTag);
- processFakeStartTag(hrTag);
- processFakeEndTag(formTag);
+ processEndTag(WTFMove(endP));
}
namespace {
-bool isLi(const HTMLStackItem* item)
+bool isLi(const HTMLStackItem& item)
{
- return item->hasTagName(liTag);
+ return item.hasTagName(liTag);
}
-bool isDdOrDt(const HTMLStackItem* item)
+bool isDdOrDt(const HTMLStackItem& item)
{
- return item->hasTagName(ddTag)
- || item->hasTagName(dtTag);
+ return item.hasTagName(ddTag) || item.hasTagName(dtTag);
}
}
-template <bool shouldClose(const HTMLStackItem*)>
-void HTMLTreeBuilder::processCloseWhenNestedTag(AtomicHTMLToken* token)
+template <bool shouldClose(const HTMLStackItem&)> void HTMLTreeBuilder::processCloseWhenNestedTag(AtomicHTMLToken&& token)
{
m_framesetOk = false;
- HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord();
- while (1) {
- RefPtr<HTMLStackItem> item = nodeRecord->stackItem();
- if (shouldClose(item.get())) {
- ASSERT(item->isElementNode());
- processFakeEndTag(item->localName());
+ for (auto* nodeRecord = &m_tree.openElements().topRecord(); ; nodeRecord = nodeRecord->next()) {
+ HTMLStackItem& item = nodeRecord->stackItem();
+ if (shouldClose(item)) {
+ ASSERT(item.isElement());
+ processFakeEndTag(item.localName());
break;
}
- if (item->isSpecialNode() && !item->hasTagName(addressTag) && !item->hasTagName(divTag) && !item->hasTagName(pTag))
+ if (isSpecialNode(item) && !item.hasTagName(addressTag) && !item.hasTagName(divTag) && !item.hasTagName(pTag))
break;
- nodeRecord = nodeRecord->next();
}
processFakePEndTagIfPInButtonScope();
- m_tree.insertHTMLElement(token);
+ m_tree.insertHTMLElement(WTFMove(token));
}
-typedef HashMap<AtomicString, QualifiedName> PrefixedNameToQualifiedNameMap;
-
-static void mapLoweredLocalNameToName(PrefixedNameToQualifiedNameMap* map, const QualifiedName* const names[], size_t length)
+template <typename TableQualifiedName> static HashMap<AtomicString, QualifiedName> createCaseMap(const TableQualifiedName* const names[], unsigned length)
{
- for (size_t i = 0; i < length; ++i) {
+ HashMap<AtomicString, QualifiedName> map;
+ for (unsigned i = 0; i < length; ++i) {
const QualifiedName& name = *names[i];
const AtomicString& localName = name.localName();
- AtomicString loweredLocalName = localName.lower();
+ AtomicString loweredLocalName = localName.convertToASCIILowercase();
if (loweredLocalName != localName)
- map->add(loweredLocalName, name);
+ map.add(loweredLocalName, name);
}
+ return map;
}
-static void adjustSVGTagNameCase(AtomicHTMLToken* token)
+static void adjustSVGTagNameCase(AtomicHTMLToken& token)
{
- static PrefixedNameToQualifiedNameMap* caseMap = 0;
- if (!caseMap) {
- caseMap = new PrefixedNameToQualifiedNameMap;
- mapLoweredLocalNameToName(caseMap, SVGNames::getSVGTags(), SVGNames::SVGTagsCount);
- }
-
- const QualifiedName& casedName = caseMap->get(token->name());
+ static NeverDestroyed<HashMap<AtomicString, QualifiedName>> map = createCaseMap(SVGNames::getSVGTags(), SVGNames::SVGTagsCount);
+ const QualifiedName& casedName = map.get().get(token.name());
if (casedName.localName().isNull())
return;
- token->setName(casedName.localName());
+ token.setName(casedName.localName());
}
-template<const QualifiedName* const * getAttrs(), unsigned length>
-static void adjustAttributes(AtomicHTMLToken* token)
+static inline void adjustAttributes(HashMap<AtomicString, QualifiedName>& map, AtomicHTMLToken& token)
{
- static PrefixedNameToQualifiedNameMap* caseMap = 0;
- if (!caseMap) {
- caseMap = new PrefixedNameToQualifiedNameMap;
- mapLoweredLocalNameToName(caseMap, getAttrs(), length);
- }
-
- for (unsigned i = 0; i < token->attributes().size(); ++i) {
- Attribute& tokenAttribute = token->attributes().at(i);
- const QualifiedName& casedName = caseMap->get(tokenAttribute.localName());
+ for (auto& attribute : token.attributes()) {
+ const QualifiedName& casedName = map.get(attribute.localName());
if (!casedName.localName().isNull())
- tokenAttribute.parserSetName(casedName);
+ attribute.parserSetName(casedName);
}
}
-static void adjustSVGAttributes(AtomicHTMLToken* token)
+template<const QualifiedName* const* attributesTable(), unsigned attributesTableLength> static void adjustAttributes(AtomicHTMLToken& token)
+{
+ static NeverDestroyed<HashMap<AtomicString, QualifiedName>> map = createCaseMap(attributesTable(), attributesTableLength);
+ adjustAttributes(map, token);
+}
+
+static inline void adjustSVGAttributes(AtomicHTMLToken& token)
{
adjustAttributes<SVGNames::getSVGAttrs, SVGNames::SVGAttrsCount>(token);
}
-static void adjustMathMLAttributes(AtomicHTMLToken* token)
+static inline void adjustMathMLAttributes(AtomicHTMLToken& token)
{
adjustAttributes<MathMLNames::getMathMLAttrs, MathMLNames::MathMLAttrsCount>(token);
}
-static void addNamesWithPrefix(PrefixedNameToQualifiedNameMap* map, const AtomicString& prefix, const QualifiedName* const names[], size_t length)
+static void addNamesWithPrefix(HashMap<AtomicString, QualifiedName>& map, const AtomicString& prefix, const QualifiedName* const names[], unsigned length)
{
- for (size_t i = 0; i < length; ++i) {
+ for (unsigned i = 0; i < length; ++i) {
const QualifiedName& name = *names[i];
const AtomicString& localName = name.localName();
- AtomicString prefixColonLocalName = prefix + ':' + localName;
- QualifiedName nameWithPrefix(prefix, localName, name.namespaceURI());
- map->add(prefixColonLocalName, nameWithPrefix);
+ map.add(prefix + ':' + localName, QualifiedName(prefix, localName, name.namespaceURI()));
}
}
-static void adjustForeignAttributes(AtomicHTMLToken* token)
+static HashMap<AtomicString, QualifiedName> createForeignAttributesMap()
{
- static PrefixedNameToQualifiedNameMap* map = 0;
- if (!map) {
- map = new PrefixedNameToQualifiedNameMap;
+ HashMap<AtomicString, QualifiedName> map;
- addNamesWithPrefix(map, xlinkAtom, XLinkNames::getXLinkAttrs(), XLinkNames::XLinkAttrsCount);
+ AtomicString xlinkName("xlink", AtomicString::ConstructFromLiteral);
+ addNamesWithPrefix(map, xlinkName, XLinkNames::getXLinkAttrs(), XLinkNames::XLinkAttrsCount);
+ addNamesWithPrefix(map, xmlAtom, XMLNames::getXMLAttrs(), XMLNames::XMLAttrsCount);
- addNamesWithPrefix(map, xmlAtom, XMLNames::getXMLAttrs(), XMLNames::XMLAttrsCount);
+ map.add(WTF::xmlnsAtom, XMLNSNames::xmlnsAttr);
+ map.add("xmlns:xlink", QualifiedName(xmlnsAtom, xlinkName, XMLNSNames::xmlnsNamespaceURI));
- map->add(WTF::xmlnsAtom, XMLNSNames::xmlnsAttr);
- map->add("xmlns:xlink", QualifiedName(xmlnsAtom, xlinkAtom, XMLNSNames::xmlnsNamespaceURI));
- }
+ return map;
+}
- for (unsigned i = 0; i < token->attributes().size(); ++i) {
- Attribute& tokenAttribute = token->attributes().at(i);
- const QualifiedName& name = map->get(tokenAttribute.localName());
- if (!name.localName().isNull())
- tokenAttribute.parserSetName(name);
- }
+static void adjustForeignAttributes(AtomicHTMLToken& token)
+{
+ static NeverDestroyed<HashMap<AtomicString, QualifiedName>> map = createForeignAttributesMap();
+ adjustAttributes(map, token);
}
-void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::StartTag);
- if (token->name() == htmlTag) {
- processHtmlStartTagForInBody(token);
+ ASSERT(token.type() == HTMLToken::StartTag);
+ if (token.name() == htmlTag) {
+ processHtmlStartTagForInBody(WTFMove(token));
return;
}
- if (token->name() == baseTag
- || token->name() == basefontTag
- || token->name() == bgsoundTag
- || token->name() == commandTag
- || token->name() == linkTag
- || token->name() == metaTag
- || token->name() == noframesTag
- || token->name() == scriptTag
- || token->name() == styleTag
- || token->name() == titleTag) {
- bool didProcess = processStartTagForInHead(token);
+ if (token.name() == baseTag
+ || token.name() == basefontTag
+ || token.name() == bgsoundTag
+ || token.name() == commandTag
+ || token.name() == linkTag
+ || token.name() == metaTag
+ || token.name() == noframesTag
+ || token.name() == scriptTag
+ || token.name() == styleTag
+ || token.name() == titleTag) {
+ bool didProcess = processStartTagForInHead(WTFMove(token));
ASSERT_UNUSED(didProcess, didProcess);
return;
}
- if (token->name() == bodyTag) {
+ if (token.name() == bodyTag) {
parseError(token);
- bool fragmentOrTemplateCase = !m_tree.openElements()->secondElementIsHTMLBodyElement() || m_tree.openElements()->hasOnlyOneElement();
-#if ENABLE(TEMPLATE_ELEMENT)
- fragmentOrTemplateCase = fragmentOrTemplateCase || m_tree.openElements()->hasTemplateInHTMLScope();
-#endif
+ bool fragmentOrTemplateCase = !m_tree.openElements().secondElementIsHTMLBodyElement() || m_tree.openElements().hasOnlyOneElement()
+ || m_tree.openElements().hasTemplateInHTMLScope();
if (fragmentOrTemplateCase) {
ASSERT(isParsingFragmentOrTemplateContents());
return;
}
m_framesetOk = false;
- m_tree.insertHTMLBodyStartTagInBody(token);
+ m_tree.insertHTMLBodyStartTagInBody(WTFMove(token));
return;
}
- if (token->name() == framesetTag) {
+ if (token.name() == framesetTag) {
parseError(token);
- if (!m_tree.openElements()->secondElementIsHTMLBodyElement() || m_tree.openElements()->hasOnlyOneElement()) {
+ if (!m_tree.openElements().secondElementIsHTMLBodyElement() || m_tree.openElements().hasOnlyOneElement()) {
ASSERT(isParsingFragmentOrTemplateContents());
return;
}
if (!m_framesetOk)
return;
- m_tree.openElements()->bodyElement()->remove(ASSERT_NO_EXCEPTION);
- m_tree.openElements()->popUntil(m_tree.openElements()->bodyElement());
- m_tree.openElements()->popHTMLBodyElement();
- ASSERT(m_tree.openElements()->top() == m_tree.openElements()->htmlElement());
- m_tree.insertHTMLElement(token);
- setInsertionMode(InsertionMode::InFrameset);
- return;
- }
- if (token->name() == addressTag
- || token->name() == articleTag
- || token->name() == asideTag
- || token->name() == blockquoteTag
- || token->name() == centerTag
- || token->name() == detailsTag
- || token->name() == dirTag
- || token->name() == divTag
- || token->name() == dlTag
- || token->name() == fieldsetTag
- || token->name() == figcaptionTag
- || token->name() == figureTag
- || token->name() == footerTag
- || token->name() == headerTag
- || token->name() == hgroupTag
- || token->name() == mainTag
- || token->name() == menuTag
- || token->name() == navTag
- || token->name() == olTag
- || token->name() == pTag
- || token->name() == sectionTag
- || token->name() == summaryTag
- || token->name() == ulTag) {
+ m_tree.openElements().bodyElement().remove();
+ m_tree.openElements().popUntil(m_tree.openElements().bodyElement());
+ m_tree.openElements().popHTMLBodyElement();
+ // Note: in the fragment case the root is a DocumentFragment instead of a proper html element which is a quirk / optimization in WebKit.
+ ASSERT(!isParsingFragment() || is<DocumentFragment>(m_tree.openElements().topNode()));
+ ASSERT(isParsingFragment() || &m_tree.openElements().top() == &m_tree.openElements().htmlElement());
+ m_tree.insertHTMLElement(WTFMove(token));
+ m_insertionMode = InsertionMode::InFrameset;
+ return;
+ }
+ if (token.name() == addressTag
+ || token.name() == articleTag
+ || token.name() == asideTag
+ || token.name() == blockquoteTag
+ || token.name() == centerTag
+ || token.name() == detailsTag
+ || token.name() == dirTag
+ || token.name() == divTag
+ || token.name() == dlTag
+ || token.name() == fieldsetTag
+ || token.name() == figcaptionTag
+ || token.name() == figureTag
+ || token.name() == footerTag
+ || token.name() == headerTag
+ || token.name() == hgroupTag
+ || token.name() == mainTag
+ || token.name() == menuTag
+ || token.name() == navTag
+ || token.name() == olTag
+ || token.name() == pTag
+ || token.name() == sectionTag
+ || token.name() == summaryTag
+ || token.name() == ulTag) {
processFakePEndTagIfPInButtonScope();
- m_tree.insertHTMLElement(token);
+ m_tree.insertHTMLElement(WTFMove(token));
return;
}
- if (isNumberedHeaderTag(token->name())) {
+ if (isNumberedHeaderTag(token.name())) {
processFakePEndTagIfPInButtonScope();
- if (m_tree.currentStackItem()->isNumberedHeaderElement()) {
+ if (isNumberedHeaderElement(m_tree.currentStackItem())) {
parseError(token);
- m_tree.openElements()->pop();
+ m_tree.openElements().pop();
}
- m_tree.insertHTMLElement(token);
+ m_tree.insertHTMLElement(WTFMove(token));
return;
}
- if (token->name() == preTag || token->name() == listingTag) {
+ if (token.name() == preTag || token.name() == listingTag) {
processFakePEndTagIfPInButtonScope();
- m_tree.insertHTMLElement(token);
+ m_tree.insertHTMLElement(WTFMove(token));
m_shouldSkipLeadingNewline = true;
m_framesetOk = false;
return;
}
- if (token->name() == formTag) {
+ if (token.name() == formTag) {
if (m_tree.form() && !isParsingTemplateContents()) {
parseError(token);
return;
}
processFakePEndTagIfPInButtonScope();
- m_tree.insertHTMLFormElement(token);
+ m_tree.insertHTMLFormElement(WTFMove(token));
return;
}
- if (token->name() == liTag) {
- processCloseWhenNestedTag<isLi>(token);
+ if (token.name() == liTag) {
+ processCloseWhenNestedTag<isLi>(WTFMove(token));
return;
}
- if (token->name() == ddTag || token->name() == dtTag) {
- processCloseWhenNestedTag<isDdOrDt>(token);
+ if (token.name() == ddTag || token.name() == dtTag) {
+ processCloseWhenNestedTag<isDdOrDt>(WTFMove(token));
return;
}
- if (token->name() == plaintextTag) {
+ if (token.name() == plaintextTag) {
processFakePEndTagIfPInButtonScope();
- m_tree.insertHTMLElement(token);
- if (m_parser.tokenizer())
- m_parser.tokenizer()->setState(HTMLTokenizer::PLAINTEXTState);
+ m_tree.insertHTMLElement(WTFMove(token));
+ m_parser.tokenizer().setPLAINTEXTState();
return;
}
- if (token->name() == buttonTag) {
- if (m_tree.openElements()->inScope(buttonTag)) {
+ if (token.name() == buttonTag) {
+ if (m_tree.openElements().inScope(buttonTag)) {
parseError(token);
processFakeEndTag(buttonTag);
- processStartTag(token); // FIXME: Could we just fall through here?
+ processStartTag(WTFMove(token)); // FIXME: Could we just fall through here?
return;
}
m_tree.reconstructTheActiveFormattingElements();
- m_tree.insertHTMLElement(token);
+ m_tree.insertHTMLElement(WTFMove(token));
m_framesetOk = false;
return;
}
- if (token->name() == aTag) {
- Element* activeATag = m_tree.activeFormattingElements()->closestElementInScopeWithName(aTag.localName());
+ if (token.name() == aTag) {
+ Element* activeATag = m_tree.activeFormattingElements().closestElementInScopeWithName(aTag.localName());
if (activeATag) {
parseError(token);
processFakeEndTag(aTag);
- m_tree.activeFormattingElements()->remove(activeATag);
- if (m_tree.openElements()->contains(activeATag))
- m_tree.openElements()->remove(activeATag);
+ m_tree.activeFormattingElements().remove(*activeATag);
+ if (m_tree.openElements().contains(*activeATag))
+ m_tree.openElements().remove(*activeATag);
}
m_tree.reconstructTheActiveFormattingElements();
- m_tree.insertFormattingElement(token);
+ m_tree.insertFormattingElement(WTFMove(token));
return;
}
- if (isNonAnchorNonNobrFormattingTag(token->name())) {
+ if (isNonAnchorNonNobrFormattingTag(token.name())) {
m_tree.reconstructTheActiveFormattingElements();
- m_tree.insertFormattingElement(token);
+ m_tree.insertFormattingElement(WTFMove(token));
return;
}
- if (token->name() == nobrTag) {
+ if (token.name() == nobrTag) {
m_tree.reconstructTheActiveFormattingElements();
- if (m_tree.openElements()->inScope(nobrTag)) {
+ if (m_tree.openElements().inScope(nobrTag)) {
parseError(token);
processFakeEndTag(nobrTag);
m_tree.reconstructTheActiveFormattingElements();
}
- m_tree.insertFormattingElement(token);
+ m_tree.insertFormattingElement(WTFMove(token));
return;
}
- if (token->name() == appletTag
- || token->name() == embedTag
- || token->name() == objectTag) {
+ if (token.name() == appletTag || token.name() == embedTag || token.name() == objectTag) {
if (!pluginContentIsAllowed(m_tree.parserContentPolicy()))
return;
}
- if (token->name() == appletTag
- || token->name() == marqueeTag
- || token->name() == objectTag) {
+ if (token.name() == appletTag || token.name() == marqueeTag || token.name() == objectTag) {
m_tree.reconstructTheActiveFormattingElements();
- m_tree.insertHTMLElement(token);
- m_tree.activeFormattingElements()->appendMarker();
+ m_tree.insertHTMLElement(WTFMove(token));
+ m_tree.activeFormattingElements().appendMarker();
m_framesetOk = false;
return;
}
- if (token->name() == tableTag) {
- if (!m_tree.inQuirksMode() && m_tree.openElements()->inButtonScope(pTag))
+ if (token.name() == tableTag) {
+ if (!m_tree.inQuirksMode() && m_tree.openElements().inButtonScope(pTag))
processFakeEndTag(pTag);
- m_tree.insertHTMLElement(token);
+ m_tree.insertHTMLElement(WTFMove(token));
m_framesetOk = false;
- setInsertionMode(InsertionMode::InTable);
+ m_insertionMode = InsertionMode::InTable;
return;
}
- if (token->name() == imageTag) {
+ if (token.name() == imageTag) {
parseError(token);
// Apparently we're not supposed to ask.
- token->setName(imgTag.localName());
+ token.setName(imgTag.localName());
// Note the fall through to the imgTag handling below!
}
- if (token->name() == areaTag
- || token->name() == brTag
- || token->name() == embedTag
- || token->name() == imgTag
- || token->name() == keygenTag
- || token->name() == wbrTag) {
+ if (token.name() == areaTag
+ || token.name() == brTag
+ || token.name() == embedTag
+ || token.name() == imgTag
+ || token.name() == keygenTag
+ || token.name() == wbrTag) {
m_tree.reconstructTheActiveFormattingElements();
- m_tree.insertSelfClosingHTMLElement(token);
+ m_tree.insertSelfClosingHTMLElement(WTFMove(token));
m_framesetOk = false;
return;
}
- if (token->name() == inputTag) {
- Attribute* typeAttribute = token->getAttributeItem(typeAttr);
+ if (token.name() == inputTag) {
m_tree.reconstructTheActiveFormattingElements();
- m_tree.insertSelfClosingHTMLElement(token);
- if (!typeAttribute || !equalIgnoringCase(typeAttribute->value(), "hidden"))
+ auto* typeAttribute = findAttribute(token.attributes(), typeAttr);
+ bool shouldClearFramesetOK = !typeAttribute || !equalLettersIgnoringASCIICase(typeAttribute->value(), "hidden");
+ m_tree.insertSelfClosingHTMLElement(WTFMove(token));
+ if (shouldClearFramesetOK)
m_framesetOk = false;
return;
}
- if (token->name() == paramTag
- || token->name() == sourceTag
- || token->name() == trackTag) {
- m_tree.insertSelfClosingHTMLElement(token);
+ if (token.name() == paramTag || token.name() == sourceTag || token.name() == trackTag) {
+ m_tree.insertSelfClosingHTMLElement(WTFMove(token));
return;
}
- if (token->name() == hrTag) {
+ if (token.name() == hrTag) {
processFakePEndTagIfPInButtonScope();
- m_tree.insertSelfClosingHTMLElement(token);
+ m_tree.insertSelfClosingHTMLElement(WTFMove(token));
m_framesetOk = false;
return;
}
- if (token->name() == isindexTag) {
- processIsindexStartTagForInBody(token);
- return;
- }
- if (token->name() == textareaTag) {
- m_tree.insertHTMLElement(token);
+ if (token.name() == textareaTag) {
+ m_tree.insertHTMLElement(WTFMove(token));
m_shouldSkipLeadingNewline = true;
- if (m_parser.tokenizer())
- m_parser.tokenizer()->setState(HTMLTokenizer::RCDATAState);
+ m_parser.tokenizer().setRCDATAState();
m_originalInsertionMode = m_insertionMode;
m_framesetOk = false;
- setInsertionMode(InsertionMode::Text);
+ m_insertionMode = InsertionMode::Text;
return;
}
- if (token->name() == xmpTag) {
+ if (token.name() == xmpTag) {
processFakePEndTagIfPInButtonScope();
m_tree.reconstructTheActiveFormattingElements();
m_framesetOk = false;
- processGenericRawTextStartTag(token);
+ processGenericRawTextStartTag(WTFMove(token));
return;
}
- if (token->name() == iframeTag) {
+ if (token.name() == iframeTag) {
m_framesetOk = false;
- processGenericRawTextStartTag(token);
+ processGenericRawTextStartTag(WTFMove(token));
return;
}
- if (token->name() == noembedTag && m_options.pluginsEnabled) {
- processGenericRawTextStartTag(token);
+ if (token.name() == noembedTag && m_options.pluginsEnabled) {
+ processGenericRawTextStartTag(WTFMove(token));
return;
}
- if (token->name() == noscriptTag && m_options.scriptEnabled) {
- processGenericRawTextStartTag(token);
+ if (token.name() == noscriptTag && m_options.scriptEnabled) {
+ processGenericRawTextStartTag(WTFMove(token));
return;
}
- if (token->name() == selectTag) {
+ if (token.name() == selectTag) {
m_tree.reconstructTheActiveFormattingElements();
- m_tree.insertHTMLElement(token);
+ m_tree.insertHTMLElement(WTFMove(token));
m_framesetOk = false;
if (m_insertionMode == InsertionMode::InTable
|| m_insertionMode == InsertionMode::InCaption
@@ -891,576 +806,556 @@ void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken* token)
|| m_insertionMode == InsertionMode::InTableBody
|| m_insertionMode == InsertionMode::InRow
|| m_insertionMode == InsertionMode::InCell)
- setInsertionMode(InsertionMode::InSelectInTable);
+ m_insertionMode = InsertionMode::InSelectInTable;
else
- setInsertionMode(InsertionMode::InSelect);
+ m_insertionMode = InsertionMode::InSelect;
return;
}
- if (token->name() == optgroupTag || token->name() == optionTag) {
- if (isHTMLOptionElement(m_tree.currentStackItem()->node())) {
+ if (token.name() == optgroupTag || token.name() == optionTag) {
+ if (is<HTMLOptionElement>(m_tree.currentStackItem().node())) {
AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
- processEndTag(&endOption);
+ processEndTag(WTFMove(endOption));
}
m_tree.reconstructTheActiveFormattingElements();
- m_tree.insertHTMLElement(token);
+ m_tree.insertHTMLElement(WTFMove(token));
return;
}
- if (token->name() == rpTag || token->name() == rtTag) {
- if (m_tree.openElements()->inScope(rubyTag.localName())) {
+ if (token.name() == rbTag || token.name() == rtcTag) {
+ if (m_tree.openElements().inScope(rubyTag.localName())) {
m_tree.generateImpliedEndTags();
- if (!m_tree.currentStackItem()->hasTagName(rubyTag))
+ if (!m_tree.currentStackItem().hasTagName(rubyTag))
parseError(token);
}
- m_tree.insertHTMLElement(token);
+ m_tree.insertHTMLElement(WTFMove(token));
return;
}
- if (token->name() == MathMLNames::mathTag.localName()) {
+ if (token.name() == rtTag || token.name() == rpTag) {
+ if (m_tree.openElements().inScope(rubyTag.localName())) {
+ m_tree.generateImpliedEndTagsWithExclusion(rtcTag.localName());
+ if (!m_tree.currentStackItem().hasTagName(rubyTag) && !m_tree.currentStackItem().hasTagName(rtcTag))
+ parseError(token);
+ }
+ m_tree.insertHTMLElement(WTFMove(token));
+ return;
+ }
+ if (token.name() == MathMLNames::mathTag.localName()) {
m_tree.reconstructTheActiveFormattingElements();
adjustMathMLAttributes(token);
adjustForeignAttributes(token);
- m_tree.insertForeignElement(token, MathMLNames::mathmlNamespaceURI);
+ m_tree.insertForeignElement(WTFMove(token), MathMLNames::mathmlNamespaceURI);
return;
}
- if (token->name() == SVGNames::svgTag.localName()) {
+ if (token.name() == SVGNames::svgTag.localName()) {
m_tree.reconstructTheActiveFormattingElements();
adjustSVGAttributes(token);
adjustForeignAttributes(token);
- m_tree.insertForeignElement(token, SVGNames::svgNamespaceURI);
+ m_tree.insertForeignElement(WTFMove(token), SVGNames::svgNamespaceURI);
return;
}
- if (isCaptionColOrColgroupTag(token->name())
- || token->name() == frameTag
- || token->name() == headTag
- || isTableBodyContextTag(token->name())
- || isTableCellContextTag(token->name())
- || token->name() == trTag) {
+ if (isCaptionColOrColgroupTag(token.name())
+ || token.name() == frameTag
+ || token.name() == headTag
+ || isTableBodyContextTag(token.name())
+ || isTableCellContextTag(token.name())
+ || token.name() == trTag) {
parseError(token);
return;
}
-#if ENABLE(TEMPLATE_ELEMENT)
- if (token->name() == templateTag) {
- processTemplateStartTag(token);
+ if (token.name() == templateTag) {
+ m_framesetOk = false;
+ processTemplateStartTag(WTFMove(token));
return;
}
-#endif
m_tree.reconstructTheActiveFormattingElements();
- m_tree.insertHTMLElement(token);
+ insertGenericHTMLElement(WTFMove(token));
}
-#if ENABLE(TEMPLATE_ELEMENT)
-void HTMLTreeBuilder::processTemplateStartTag(AtomicHTMLToken* token)
+inline void HTMLTreeBuilder::insertGenericHTMLElement(AtomicHTMLToken&& token)
{
- m_tree.activeFormattingElements()->appendMarker();
- m_tree.insertHTMLElement(token);
+ m_customElementToConstruct = m_tree.insertHTMLElementOrFindCustomElementInterface(WTFMove(token));
+}
+
+void HTMLTreeBuilder::didCreateCustomOrCallbackElement(Ref<Element>&& element, CustomElementConstructionData& data)
+{
+ m_tree.insertCustomElement(WTFMove(element), data.name, WTFMove(data.attributes));
+}
+
+void HTMLTreeBuilder::processTemplateStartTag(AtomicHTMLToken&& token)
+{
+ m_tree.activeFormattingElements().appendMarker();
+ m_tree.insertHTMLElement(WTFMove(token));
m_templateInsertionModes.append(InsertionMode::TemplateContents);
- setInsertionMode(InsertionMode::TemplateContents);
+ m_insertionMode = InsertionMode::TemplateContents;
}
-bool HTMLTreeBuilder::processTemplateEndTag(AtomicHTMLToken* token)
+bool HTMLTreeBuilder::processTemplateEndTag(AtomicHTMLToken&& token)
{
- ASSERT(token->name() == templateTag.localName());
- if (!m_tree.openElements()->hasTemplateInHTMLScope()) {
- ASSERT(m_templateInsertionModes.isEmpty() || (m_templateInsertionModes.size() == 1 && m_fragmentContext.contextElement()->hasTagName(templateTag)));
+ ASSERT(token.name() == templateTag.localName());
+ if (!m_tree.openElements().hasTemplateInHTMLScope()) {
+ ASSERT(m_templateInsertionModes.isEmpty() || (m_templateInsertionModes.size() == 1 && m_fragmentContext.contextElement().hasTagName(templateTag)));
parseError(token);
return false;
}
m_tree.generateImpliedEndTags();
- if (!m_tree.currentStackItem()->hasTagName(templateTag))
+ if (!m_tree.currentStackItem().hasTagName(templateTag))
parseError(token);
- m_tree.openElements()->popUntilPopped(templateTag);
- m_tree.activeFormattingElements()->clearToLastMarker();
+ m_tree.openElements().popUntilPopped(templateTag);
+ m_tree.activeFormattingElements().clearToLastMarker();
m_templateInsertionModes.removeLast();
resetInsertionModeAppropriately();
return true;
}
-bool HTMLTreeBuilder::processEndOfFileForInTemplateContents(AtomicHTMLToken* token)
+bool HTMLTreeBuilder::processEndOfFileForInTemplateContents(AtomicHTMLToken&& token)
{
AtomicHTMLToken endTemplate(HTMLToken::EndTag, templateTag.localName());
- if (!processTemplateEndTag(&endTemplate))
+ if (!processTemplateEndTag(WTFMove(endTemplate)))
return false;
- processEndOfFile(token);
+ processEndOfFile(WTFMove(token));
return true;
}
-#endif
bool HTMLTreeBuilder::processColgroupEndTagForInColumnGroup()
{
- bool ignoreFakeEndTag = m_tree.currentIsRootNode();
-#if ENABLE(TEMPLATE_ELEMENT)
- ignoreFakeEndTag = ignoreFakeEndTag || m_tree.currentNode()->hasTagName(templateTag);
-#endif
+ bool ignoreFakeEndTag = m_tree.currentIsRootNode() || m_tree.currentNode().hasTagName(templateTag);
if (ignoreFakeEndTag) {
ASSERT(isParsingFragmentOrTemplateContents());
// FIXME: parse error
return false;
}
- m_tree.openElements()->pop();
- setInsertionMode(InsertionMode::InTable);
+ m_tree.openElements().pop();
+ m_insertionMode = InsertionMode::InTable;
return true;
}
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#close-the-cell
void HTMLTreeBuilder::closeTheCell()
{
- ASSERT(insertionMode() == InsertionMode::InCell);
- if (m_tree.openElements()->inTableScope(tdTag)) {
- ASSERT(!m_tree.openElements()->inTableScope(thTag));
+ ASSERT(m_insertionMode == InsertionMode::InCell);
+ if (m_tree.openElements().inTableScope(tdTag)) {
+ ASSERT(!m_tree.openElements().inTableScope(thTag));
processFakeEndTag(tdTag);
return;
}
- ASSERT(m_tree.openElements()->inTableScope(thTag));
+ ASSERT(m_tree.openElements().inTableScope(thTag));
processFakeEndTag(thTag);
- ASSERT(insertionMode() == InsertionMode::InRow);
+ ASSERT(m_insertionMode == InsertionMode::InRow);
}
-void HTMLTreeBuilder::processStartTagForInTable(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processStartTagForInTable(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::StartTag);
- if (token->name() == captionTag) {
- m_tree.openElements()->popUntilTableScopeMarker();
- m_tree.activeFormattingElements()->appendMarker();
- m_tree.insertHTMLElement(token);
- setInsertionMode(InsertionMode::InCaption);
+ ASSERT(token.type() == HTMLToken::StartTag);
+ if (token.name() == captionTag) {
+ m_tree.openElements().popUntilTableScopeMarker();
+ m_tree.activeFormattingElements().appendMarker();
+ m_tree.insertHTMLElement(WTFMove(token));
+ m_insertionMode = InsertionMode::InCaption;
return;
}
- if (token->name() == colgroupTag) {
- m_tree.openElements()->popUntilTableScopeMarker();
- m_tree.insertHTMLElement(token);
- setInsertionMode(InsertionMode::InColumnGroup);
+ if (token.name() == colgroupTag) {
+ m_tree.openElements().popUntilTableScopeMarker();
+ m_tree.insertHTMLElement(WTFMove(token));
+ m_insertionMode = InsertionMode::InColumnGroup;
return;
}
- if (token->name() == colTag) {
+ if (token.name() == colTag) {
processFakeStartTag(colgroupTag);
- ASSERT(insertionMode() == InsertionMode::InColumnGroup);
- processStartTag(token);
+ ASSERT(m_insertionMode == InsertionMode::InColumnGroup);
+ processStartTag(WTFMove(token));
return;
}
- if (isTableBodyContextTag(token->name())) {
- m_tree.openElements()->popUntilTableScopeMarker();
- m_tree.insertHTMLElement(token);
- setInsertionMode(InsertionMode::InTableBody);
+ if (isTableBodyContextTag(token.name())) {
+ m_tree.openElements().popUntilTableScopeMarker();
+ m_tree.insertHTMLElement(WTFMove(token));
+ m_insertionMode = InsertionMode::InTableBody;
return;
}
- if (isTableCellContextTag(token->name())
- || token->name() == trTag) {
+ if (isTableCellContextTag(token.name()) || token.name() == trTag) {
processFakeStartTag(tbodyTag);
- ASSERT(insertionMode() == InsertionMode::InTableBody);
- processStartTag(token);
+ ASSERT(m_insertionMode == InsertionMode::InTableBody);
+ processStartTag(WTFMove(token));
return;
}
- if (token->name() == tableTag) {
+ if (token.name() == tableTag) {
parseError(token);
if (!processTableEndTagForInTable()) {
ASSERT(isParsingFragmentOrTemplateContents());
return;
}
- processStartTag(token);
+ processStartTag(WTFMove(token));
return;
}
- if (token->name() == styleTag || token->name() == scriptTag) {
- processStartTagForInHead(token);
+ if (token.name() == styleTag || token.name() == scriptTag) {
+ processStartTagForInHead(WTFMove(token));
return;
}
- if (token->name() == inputTag) {
- Attribute* typeAttribute = token->getAttributeItem(typeAttr);
- if (typeAttribute && equalIgnoringCase(typeAttribute->value(), "hidden")) {
+ if (token.name() == inputTag) {
+ auto* typeAttribute = findAttribute(token.attributes(), typeAttr);
+ if (typeAttribute && equalLettersIgnoringASCIICase(typeAttribute->value(), "hidden")) {
parseError(token);
- m_tree.insertSelfClosingHTMLElement(token);
+ m_tree.insertSelfClosingHTMLElement(WTFMove(token));
return;
}
// Fall through to "anything else" case.
}
- if (token->name() == formTag) {
+ if (token.name() == formTag) {
parseError(token);
if (m_tree.form() && !isParsingTemplateContents())
return;
- m_tree.insertHTMLFormElement(token, true);
- m_tree.openElements()->pop();
+ m_tree.insertHTMLFormElement(WTFMove(token), true);
+ m_tree.openElements().pop();
return;
}
-#if ENABLE(TEMPLATE_ELEMENT)
- if (token->name() == templateTag) {
- processTemplateStartTag(token);
+ if (token.name() == templateTag) {
+ processTemplateStartTag(WTFMove(token));
return;
}
-#endif
parseError(token);
HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree);
- processStartTagForInBody(token);
+ processStartTagForInBody(WTFMove(token));
}
-void HTMLTreeBuilder::processStartTag(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processStartTag(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::StartTag);
- switch (insertionMode()) {
+ ASSERT(token.type() == HTMLToken::StartTag);
+ switch (m_insertionMode) {
case InsertionMode::Initial:
- ASSERT(insertionMode() == InsertionMode::Initial);
defaultForInitial();
+ ASSERT(m_insertionMode == InsertionMode::BeforeHTML);
FALLTHROUGH;
case InsertionMode::BeforeHTML:
- ASSERT(insertionMode() == InsertionMode::BeforeHTML);
- if (token->name() == htmlTag) {
- m_tree.insertHTMLHtmlStartTagBeforeHTML(token);
- setInsertionMode(InsertionMode::BeforeHead);
+ if (token.name() == htmlTag) {
+ m_tree.insertHTMLHtmlStartTagBeforeHTML(WTFMove(token));
+ m_insertionMode = InsertionMode::BeforeHead;
return;
}
defaultForBeforeHTML();
+ ASSERT(m_insertionMode == InsertionMode::BeforeHead);
FALLTHROUGH;
case InsertionMode::BeforeHead:
- ASSERT(insertionMode() == InsertionMode::BeforeHead);
- if (token->name() == htmlTag) {
- processHtmlStartTagForInBody(token);
+ if (token.name() == htmlTag) {
+ processHtmlStartTagForInBody(WTFMove(token));
return;
}
- if (token->name() == headTag) {
- m_tree.insertHTMLHeadElement(token);
- setInsertionMode(InsertionMode::InHead);
+ if (token.name() == headTag) {
+ m_tree.insertHTMLHeadElement(WTFMove(token));
+ m_insertionMode = InsertionMode::InHead;
return;
}
defaultForBeforeHead();
+ ASSERT(m_insertionMode == InsertionMode::InHead);
FALLTHROUGH;
case InsertionMode::InHead:
- ASSERT(insertionMode() == InsertionMode::InHead);
- if (processStartTagForInHead(token))
+ if (processStartTagForInHead(WTFMove(token)))
return;
defaultForInHead();
+ ASSERT(m_insertionMode == InsertionMode::AfterHead);
FALLTHROUGH;
case InsertionMode::AfterHead:
- ASSERT(insertionMode() == InsertionMode::AfterHead);
- if (token->name() == htmlTag) {
- processHtmlStartTagForInBody(token);
+ if (token.name() == htmlTag) {
+ processHtmlStartTagForInBody(WTFMove(token));
return;
}
- if (token->name() == bodyTag) {
+ if (token.name() == bodyTag) {
m_framesetOk = false;
- m_tree.insertHTMLBodyElement(token);
- setInsertionMode(InsertionMode::InBody);
+ m_tree.insertHTMLBodyElement(WTFMove(token));
+ m_insertionMode = InsertionMode::InBody;
return;
}
- if (token->name() == framesetTag) {
- m_tree.insertHTMLElement(token);
- setInsertionMode(InsertionMode::InFrameset);
+ if (token.name() == framesetTag) {
+ m_tree.insertHTMLElement(WTFMove(token));
+ m_insertionMode = InsertionMode::InFrameset;
return;
}
- if (token->name() == baseTag
- || token->name() == basefontTag
- || token->name() == bgsoundTag
- || token->name() == linkTag
- || token->name() == metaTag
- || token->name() == noframesTag
- || token->name() == scriptTag
- || token->name() == styleTag
-#if ENABLE(TEMPLATE_ELEMENT)
- || token->name() == templateTag
-#endif
- || token->name() == titleTag) {
+ if (token.name() == baseTag
+ || token.name() == basefontTag
+ || token.name() == bgsoundTag
+ || token.name() == linkTag
+ || token.name() == metaTag
+ || token.name() == noframesTag
+ || token.name() == scriptTag
+ || token.name() == styleTag
+ || token.name() == templateTag
+ || token.name() == titleTag) {
parseError(token);
- ASSERT(m_tree.head());
- m_tree.openElements()->pushHTMLHeadElement(m_tree.headStackItem());
- processStartTagForInHead(token);
- m_tree.openElements()->removeHTMLHeadElement(m_tree.head());
+ ASSERT(m_tree.headStackItem());
+ m_tree.openElements().pushHTMLHeadElement(*m_tree.headStackItem());
+ processStartTagForInHead(WTFMove(token));
+ m_tree.openElements().removeHTMLHeadElement(m_tree.head());
return;
}
- if (token->name() == headTag) {
+ if (token.name() == headTag) {
parseError(token);
return;
}
defaultForAfterHead();
+ ASSERT(m_insertionMode == InsertionMode::InBody);
FALLTHROUGH;
case InsertionMode::InBody:
- ASSERT(insertionMode() == InsertionMode::InBody);
- processStartTagForInBody(token);
+ processStartTagForInBody(WTFMove(token));
break;
case InsertionMode::InTable:
- ASSERT(insertionMode() == InsertionMode::InTable);
- processStartTagForInTable(token);
+ processStartTagForInTable(WTFMove(token));
break;
case InsertionMode::InCaption:
- ASSERT(insertionMode() == InsertionMode::InCaption);
- if (isCaptionColOrColgroupTag(token->name())
- || isTableBodyContextTag(token->name())
- || isTableCellContextTag(token->name())
- || token->name() == trTag) {
+ if (isCaptionColOrColgroupTag(token.name())
+ || isTableBodyContextTag(token.name())
+ || isTableCellContextTag(token.name())
+ || token.name() == trTag) {
parseError(token);
if (!processCaptionEndTagForInCaption()) {
ASSERT(isParsingFragment());
return;
}
- processStartTag(token);
+ processStartTag(WTFMove(token));
return;
}
- processStartTagForInBody(token);
+ processStartTagForInBody(WTFMove(token));
break;
case InsertionMode::InColumnGroup:
- ASSERT(insertionMode() == InsertionMode::InColumnGroup);
- if (token->name() == htmlTag) {
- processHtmlStartTagForInBody(token);
+ if (token.name() == htmlTag) {
+ processHtmlStartTagForInBody(WTFMove(token));
return;
}
- if (token->name() == colTag) {
- m_tree.insertSelfClosingHTMLElement(token);
+ if (token.name() == colTag) {
+ m_tree.insertSelfClosingHTMLElement(WTFMove(token));
return;
}
-#if ENABLE(TEMPLATE_ELEMENT)
- if (token->name() == templateTag) {
- processTemplateStartTag(token);
+ if (token.name() == templateTag) {
+ processTemplateStartTag(WTFMove(token));
return;
}
-#endif
if (!processColgroupEndTagForInColumnGroup()) {
ASSERT(isParsingFragmentOrTemplateContents());
return;
}
- processStartTag(token);
+ processStartTag(WTFMove(token));
break;
case InsertionMode::InTableBody:
- ASSERT(insertionMode() == InsertionMode::InTableBody);
- if (token->name() == trTag) {
- m_tree.openElements()->popUntilTableBodyScopeMarker(); // How is there ever anything to pop?
- m_tree.insertHTMLElement(token);
- setInsertionMode(InsertionMode::InRow);
+ if (token.name() == trTag) {
+ m_tree.openElements().popUntilTableBodyScopeMarker(); // How is there ever anything to pop?
+ m_tree.insertHTMLElement(WTFMove(token));
+ m_insertionMode = InsertionMode::InRow;
return;
}
- if (isTableCellContextTag(token->name())) {
+ if (isTableCellContextTag(token.name())) {
parseError(token);
processFakeStartTag(trTag);
- ASSERT(insertionMode() == InsertionMode::InRow);
- processStartTag(token);
+ ASSERT(m_insertionMode == InsertionMode::InRow);
+ processStartTag(WTFMove(token));
return;
}
- if (isCaptionColOrColgroupTag(token->name()) || isTableBodyContextTag(token->name())) {
+ if (isCaptionColOrColgroupTag(token.name()) || isTableBodyContextTag(token.name())) {
// FIXME: This is slow.
- if (!m_tree.openElements()->inTableScope(tbodyTag) && !m_tree.openElements()->inTableScope(theadTag) && !m_tree.openElements()->inTableScope(tfootTag)) {
+ if (!m_tree.openElements().inTableScope(tbodyTag) && !m_tree.openElements().inTableScope(theadTag) && !m_tree.openElements().inTableScope(tfootTag)) {
ASSERT(isParsingFragmentOrTemplateContents());
parseError(token);
return;
}
- m_tree.openElements()->popUntilTableBodyScopeMarker();
- ASSERT(isTableBodyContextTag(m_tree.currentStackItem()->localName()));
- processFakeEndTag(m_tree.currentStackItem()->localName());
- processStartTag(token);
+ m_tree.openElements().popUntilTableBodyScopeMarker();
+ ASSERT(isTableBodyContextTag(m_tree.currentStackItem().localName()));
+ processFakeEndTag(m_tree.currentStackItem().localName());
+ processStartTag(WTFMove(token));
return;
}
- processStartTagForInTable(token);
+ processStartTagForInTable(WTFMove(token));
break;
case InsertionMode::InRow:
- ASSERT(insertionMode() == InsertionMode::InRow);
- if (isTableCellContextTag(token->name())) {
- m_tree.openElements()->popUntilTableRowScopeMarker();
- m_tree.insertHTMLElement(token);
- setInsertionMode(InsertionMode::InCell);
- m_tree.activeFormattingElements()->appendMarker();
+ if (isTableCellContextTag(token.name())) {
+ m_tree.openElements().popUntilTableRowScopeMarker();
+ m_tree.insertHTMLElement(WTFMove(token));
+ m_insertionMode = InsertionMode::InCell;
+ m_tree.activeFormattingElements().appendMarker();
return;
}
- if (token->name() == trTag
- || isCaptionColOrColgroupTag(token->name())
- || isTableBodyContextTag(token->name())) {
+ if (token.name() == trTag
+ || isCaptionColOrColgroupTag(token.name())
+ || isTableBodyContextTag(token.name())) {
if (!processTrEndTagForInRow()) {
ASSERT(isParsingFragmentOrTemplateContents());
return;
}
- ASSERT(insertionMode() == InsertionMode::InTableBody);
- processStartTag(token);
+ ASSERT(m_insertionMode == InsertionMode::InTableBody);
+ processStartTag(WTFMove(token));
return;
}
- processStartTagForInTable(token);
+ processStartTagForInTable(WTFMove(token));
break;
case InsertionMode::InCell:
- ASSERT(insertionMode() == InsertionMode::InCell);
- if (isCaptionColOrColgroupTag(token->name())
- || isTableCellContextTag(token->name())
- || token->name() == trTag
- || isTableBodyContextTag(token->name())) {
+ if (isCaptionColOrColgroupTag(token.name())
+ || isTableCellContextTag(token.name())
+ || token.name() == trTag
+ || isTableBodyContextTag(token.name())) {
// FIXME: This could be more efficient.
- if (!m_tree.openElements()->inTableScope(tdTag) && !m_tree.openElements()->inTableScope(thTag)) {
+ if (!m_tree.openElements().inTableScope(tdTag) && !m_tree.openElements().inTableScope(thTag)) {
ASSERT(isParsingFragment());
parseError(token);
return;
}
closeTheCell();
- processStartTag(token);
+ processStartTag(WTFMove(token));
return;
}
- processStartTagForInBody(token);
+ processStartTagForInBody(WTFMove(token));
break;
case InsertionMode::AfterBody:
case InsertionMode::AfterAfterBody:
- ASSERT(insertionMode() == InsertionMode::AfterBody || insertionMode() == InsertionMode::AfterAfterBody);
- if (token->name() == htmlTag) {
- processHtmlStartTagForInBody(token);
+ if (token.name() == htmlTag) {
+ processHtmlStartTagForInBody(WTFMove(token));
return;
}
- setInsertionMode(InsertionMode::InBody);
- processStartTag(token);
+ m_insertionMode = InsertionMode::InBody;
+ processStartTag(WTFMove(token));
break;
case InsertionMode::InHeadNoscript:
- ASSERT(insertionMode() == InsertionMode::InHeadNoscript);
- if (token->name() == htmlTag) {
- processHtmlStartTagForInBody(token);
- return;
- }
- if (token->name() == basefontTag
- || token->name() == bgsoundTag
- || token->name() == linkTag
- || token->name() == metaTag
- || token->name() == noframesTag
- || token->name() == styleTag) {
- bool didProcess = processStartTagForInHead(token);
+ if (token.name() == htmlTag) {
+ processHtmlStartTagForInBody(WTFMove(token));
+ return;
+ }
+ if (token.name() == basefontTag
+ || token.name() == bgsoundTag
+ || token.name() == linkTag
+ || token.name() == metaTag
+ || token.name() == noframesTag
+ || token.name() == styleTag) {
+ bool didProcess = processStartTagForInHead(WTFMove(token));
ASSERT_UNUSED(didProcess, didProcess);
return;
}
- if (token->name() == htmlTag || token->name() == noscriptTag) {
+ if (token.name() == htmlTag || token.name() == noscriptTag) {
parseError(token);
return;
}
defaultForInHeadNoscript();
- processToken(token);
+ processToken(WTFMove(token));
break;
case InsertionMode::InFrameset:
- ASSERT(insertionMode() == InsertionMode::InFrameset);
- if (token->name() == htmlTag) {
- processHtmlStartTagForInBody(token);
- return;
- }
- if (token->name() == framesetTag) {
- m_tree.insertHTMLElement(token);
+ if (token.name() == htmlTag) {
+ processHtmlStartTagForInBody(WTFMove(token));
return;
}
- if (token->name() == frameTag) {
- m_tree.insertSelfClosingHTMLElement(token);
+ if (token.name() == framesetTag) {
+ m_tree.insertHTMLElement(WTFMove(token));
return;
}
- if (token->name() == noframesTag) {
- processStartTagForInHead(token);
+ if (token.name() == frameTag) {
+ m_tree.insertSelfClosingHTMLElement(WTFMove(token));
return;
}
-#if ENABLE(TEMPLATE_ELEMENT)
- if (token->name() == templateTag) {
- processTemplateStartTag(token);
+ if (token.name() == noframesTag) {
+ processStartTagForInHead(WTFMove(token));
return;
}
-#endif
parseError(token);
break;
case InsertionMode::AfterFrameset:
case InsertionMode::AfterAfterFrameset:
- ASSERT(insertionMode() == InsertionMode::AfterFrameset || insertionMode() == InsertionMode::AfterAfterFrameset);
- if (token->name() == htmlTag) {
- processHtmlStartTagForInBody(token);
+ if (token.name() == htmlTag) {
+ processHtmlStartTagForInBody(WTFMove(token));
return;
}
- if (token->name() == noframesTag) {
- processStartTagForInHead(token);
+ if (token.name() == noframesTag) {
+ processStartTagForInHead(WTFMove(token));
return;
}
parseError(token);
break;
case InsertionMode::InSelectInTable:
- ASSERT(insertionMode() == InsertionMode::InSelectInTable);
- if (token->name() == captionTag
- || token->name() == tableTag
- || isTableBodyContextTag(token->name())
- || token->name() == trTag
- || isTableCellContextTag(token->name())) {
+ if (token.name() == captionTag
+ || token.name() == tableTag
+ || isTableBodyContextTag(token.name())
+ || token.name() == trTag
+ || isTableCellContextTag(token.name())) {
parseError(token);
AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
- processEndTag(&endSelect);
- processStartTag(token);
+ processEndTag(WTFMove(endSelect));
+ processStartTag(WTFMove(token));
return;
}
FALLTHROUGH;
case InsertionMode::InSelect:
- ASSERT(insertionMode() == InsertionMode::InSelect || insertionMode() == InsertionMode::InSelectInTable);
- if (token->name() == htmlTag) {
- processHtmlStartTagForInBody(token);
+ if (token.name() == htmlTag) {
+ processHtmlStartTagForInBody(WTFMove(token));
return;
}
- if (token->name() == optionTag) {
- if (isHTMLOptionElement(m_tree.currentStackItem()->node())) {
+ if (token.name() == optionTag) {
+ if (is<HTMLOptionElement>(m_tree.currentStackItem().node())) {
AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
- processEndTag(&endOption);
+ processEndTag(WTFMove(endOption));
}
- m_tree.insertHTMLElement(token);
+ m_tree.insertHTMLElement(WTFMove(token));
return;
}
- if (token->name() == optgroupTag) {
- if (isHTMLOptionElement(m_tree.currentStackItem()->node())) {
+ if (token.name() == optgroupTag) {
+ if (is<HTMLOptionElement>(m_tree.currentStackItem().node())) {
AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName());
- processEndTag(&endOption);
+ processEndTag(WTFMove(endOption));
}
- if (isHTMLOptGroupElement(m_tree.currentStackItem()->node())) {
+ if (is<HTMLOptGroupElement>(m_tree.currentStackItem().node())) {
AtomicHTMLToken endOptgroup(HTMLToken::EndTag, optgroupTag.localName());
- processEndTag(&endOptgroup);
+ processEndTag(WTFMove(endOptgroup));
}
- m_tree.insertHTMLElement(token);
+ m_tree.insertHTMLElement(WTFMove(token));
return;
}
- if (token->name() == selectTag) {
+ if (token.name() == selectTag) {
parseError(token);
AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
- processEndTag(&endSelect);
+ processEndTag(WTFMove(endSelect));
return;
}
- if (token->name() == inputTag
- || token->name() == keygenTag
- || token->name() == textareaTag) {
+ if (token.name() == inputTag || token.name() == keygenTag || token.name() == textareaTag) {
parseError(token);
- if (!m_tree.openElements()->inSelectScope(selectTag)) {
+ if (!m_tree.openElements().inSelectScope(selectTag)) {
ASSERT(isParsingFragment());
return;
}
AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
- processEndTag(&endSelect);
- processStartTag(token);
+ processEndTag(WTFMove(endSelect));
+ processStartTag(WTFMove(token));
return;
}
- if (token->name() == scriptTag) {
- bool didProcess = processStartTagForInHead(token);
+ if (token.name() == scriptTag) {
+ bool didProcess = processStartTagForInHead(WTFMove(token));
ASSERT_UNUSED(didProcess, didProcess);
return;
}
-#if ENABLE(TEMPLATE_ELEMENT)
- if (token->name() == templateTag) {
- processTemplateStartTag(token);
+ if (token.name() == templateTag) {
+ processTemplateStartTag(WTFMove(token));
return;
}
-#endif
break;
case InsertionMode::InTableText:
defaultForInTableText();
- processStartTag(token);
+ processStartTag(WTFMove(token));
break;
case InsertionMode::Text:
ASSERT_NOT_REACHED();
break;
case InsertionMode::TemplateContents:
-#if ENABLE(TEMPLATE_ELEMENT)
- if (token->name() == templateTag) {
- processTemplateStartTag(token);
+ if (token.name() == templateTag) {
+ processTemplateStartTag(WTFMove(token));
return;
}
- if (token->name() == linkTag
- || token->name() == scriptTag
- || token->name() == styleTag
- || token->name() == metaTag) {
- processStartTagForInHead(token);
+ if (token.name() == linkTag
+ || token.name() == scriptTag
+ || token.name() == styleTag
+ || token.name() == metaTag) {
+ processStartTagForInHead(WTFMove(token));
return;
}
InsertionMode insertionMode = InsertionMode::TemplateContents;
- if (token->name() == frameTag)
- insertionMode = InsertionMode::InFrameset;
- else if (token->name() == colTag)
+ if (token.name() == colTag)
insertionMode = InsertionMode::InColumnGroup;
- else if (isCaptionColOrColgroupTag(token->name()) || isTableBodyContextTag(token->name()))
+ else if (isCaptionColOrColgroupTag(token.name()) || isTableBodyContextTag(token.name()))
insertionMode = InsertionMode::InTable;
- else if (token->name() == trTag)
+ else if (token.name() == trTag)
insertionMode = InsertionMode::InTableBody;
- else if (isTableCellContextTag(token->name()))
+ else if (isTableCellContextTag(token.name()))
insertionMode = InsertionMode::InRow;
else
insertionMode = InsertionMode::InBody;
@@ -1468,64 +1363,57 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken* token)
ASSERT(insertionMode != InsertionMode::TemplateContents);
ASSERT(m_templateInsertionModes.last() == InsertionMode::TemplateContents);
m_templateInsertionModes.last() = insertionMode;
- setInsertionMode(insertionMode);
+ m_insertionMode = insertionMode;
- processStartTag(token);
-#else
- ASSERT_NOT_REACHED();
-#endif
+ processStartTag(WTFMove(token));
break;
}
}
-void HTMLTreeBuilder::processHtmlStartTagForInBody(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processHtmlStartTagForInBody(AtomicHTMLToken&& token)
{
parseError(token);
-#if ENABLE(TEMPLATE_ELEMENT)
- if (m_tree.openElements()->hasTemplateInHTMLScope()) {
+ if (m_tree.openElements().hasTemplateInHTMLScope()) {
ASSERT(isParsingTemplateContents());
return;
}
-#endif
- m_tree.insertHTMLHtmlStartTagInBody(token);
+ m_tree.insertHTMLHtmlStartTagInBody(WTFMove(token));
}
-bool HTMLTreeBuilder::processBodyEndTagForInBody(AtomicHTMLToken* token)
+bool HTMLTreeBuilder::processBodyEndTagForInBody(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::EndTag);
- ASSERT(token->name() == bodyTag);
- if (!m_tree.openElements()->inScope(bodyTag.localName())) {
+ ASSERT(token.type() == HTMLToken::EndTag);
+ ASSERT(token.name() == bodyTag);
+ if (!m_tree.openElements().inScope(bodyTag.localName())) {
parseError(token);
return false;
}
notImplemented(); // Emit a more specific parse error based on stack contents.
- setInsertionMode(InsertionMode::AfterBody);
+ m_insertionMode = InsertionMode::AfterBody;
return true;
}
-void HTMLTreeBuilder::processAnyOtherEndTagForInBody(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processAnyOtherEndTagForInBody(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::EndTag);
- HTMLElementStack::ElementRecord* record = m_tree.openElements()->topRecord();
- while (1) {
- RefPtr<HTMLStackItem> item = record->stackItem();
- if (item->matchesHTMLTag(token->name())) {
- m_tree.generateImpliedEndTagsWithExclusion(token->name());
- if (!m_tree.currentStackItem()->matchesHTMLTag(token->name()))
+ ASSERT(token.type() == HTMLToken::EndTag);
+ for (auto* record = &m_tree.openElements().topRecord(); ; record = record->next()) {
+ HTMLStackItem& item = record->stackItem();
+ if (item.matchesHTMLTag(token.name())) {
+ m_tree.generateImpliedEndTagsWithExclusion(token.name());
+ if (!m_tree.currentStackItem().matchesHTMLTag(token.name()))
parseError(token);
- m_tree.openElements()->popUntilPopped(item->element());
+ m_tree.openElements().popUntilPopped(item.element());
return;
}
- if (item->isSpecialNode()) {
+ if (isSpecialNode(item)) {
parseError(token);
return;
}
- record = record->next();
}
}
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-inbody
-void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken* token)
+void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken& token)
{
// The adoption agency algorithm is N^2. We limit the number of iterations
// to stop from hanging the whole browser. This limit is specified in the
@@ -1537,43 +1425,43 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken* token)
// 1, 2, 3 and 16 are covered by the for() loop.
for (int i = 0; i < outerIterationLimit; ++i) {
// 4.
- Element* formattingElement = m_tree.activeFormattingElements()->closestElementInScopeWithName(token->name());
+ Element* formattingElement = m_tree.activeFormattingElements().closestElementInScopeWithName(token.name());
// 4.a
if (!formattingElement)
- return processAnyOtherEndTagForInBody(token);
+ return processAnyOtherEndTagForInBody(WTFMove(token));
// 4.c
- if ((m_tree.openElements()->contains(formattingElement)) && !m_tree.openElements()->inScope(formattingElement)) {
+ if ((m_tree.openElements().contains(*formattingElement)) && !m_tree.openElements().inScope(*formattingElement)) {
parseError(token);
notImplemented(); // Check the stack of open elements for a more specific parse error.
return;
}
// 4.b
- HTMLElementStack::ElementRecord* formattingElementRecord = m_tree.openElements()->find(formattingElement);
+ auto* formattingElementRecord = m_tree.openElements().find(*formattingElement);
if (!formattingElementRecord) {
parseError(token);
- m_tree.activeFormattingElements()->remove(formattingElement);
+ m_tree.activeFormattingElements().remove(*formattingElement);
return;
}
// 4.d
- if (formattingElement != m_tree.currentElement())
+ if (formattingElement != &m_tree.currentElement())
parseError(token);
// 5.
- HTMLElementStack::ElementRecord* furthestBlock = m_tree.openElements()->furthestBlockForFormattingElement(formattingElement);
+ auto* furthestBlock = m_tree.openElements().furthestBlockForFormattingElement(*formattingElement);
// 6.
if (!furthestBlock) {
- m_tree.openElements()->popUntilPopped(formattingElement);
- m_tree.activeFormattingElements()->remove(formattingElement);
+ m_tree.openElements().popUntilPopped(*formattingElement);
+ m_tree.activeFormattingElements().remove(*formattingElement);
return;
}
// 7.
- ASSERT(furthestBlock->isAbove(formattingElementRecord));
- RefPtr<HTMLStackItem> commonAncestor = formattingElementRecord->next()->stackItem();
+ ASSERT(furthestBlock->isAbove(*formattingElementRecord));
+ Ref<HTMLStackItem> commonAncestor = formattingElementRecord->next()->stackItem();
// 8.
- HTMLFormattingElementList::Bookmark bookmark = m_tree.activeFormattingElements()->bookmarkFor(formattingElement);
+ HTMLFormattingElementList::Bookmark bookmark = m_tree.activeFormattingElements().bookmarkFor(*formattingElement);
// 9.
- HTMLElementStack::ElementRecord* node = furthestBlock;
- HTMLElementStack::ElementRecord* nextNode = node->next();
- HTMLElementStack::ElementRecord* lastNode = furthestBlock;
+ auto* node = furthestBlock;
+ auto* nextNode = node->next();
+ auto* lastNode = furthestBlock;
// 9.1, 9.2, 9.3 and 9.11 are covered by the for() loop.
for (int i = 0; i < innerIterationLimit; ++i) {
// 9.4
@@ -1581,8 +1469,8 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken* token)
ASSERT(node);
nextNode = node->next(); // Save node->next() for the next iteration in case node is deleted in 9.5.
// 9.5
- if (!m_tree.activeFormattingElements()->contains(node->element())) {
- m_tree.openElements()->remove(node->element());
+ if (!m_tree.activeFormattingElements().contains(node->element())) {
+ m_tree.openElements().remove(node->element());
node = 0;
continue;
}
@@ -1590,33 +1478,31 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken* token)
if (node == formattingElementRecord)
break;
// 9.7
- RefPtr<HTMLStackItem> newItem = m_tree.createElementFromSavedToken(node->stackItem().get());
+ auto newItem = m_tree.createElementFromSavedToken(node->stackItem());
- HTMLFormattingElementList::Entry* nodeEntry = m_tree.activeFormattingElements()->find(node->element());
- nodeEntry->replaceElement(newItem);
- node->replaceElement(newItem.release());
+ HTMLFormattingElementList::Entry* nodeEntry = m_tree.activeFormattingElements().find(node->element());
+ nodeEntry->replaceElement(newItem.copyRef());
+ node->replaceElement(WTFMove(newItem));
// 9.8
if (lastNode == furthestBlock)
- bookmark.moveToAfter(nodeEntry);
+ bookmark.moveToAfter(*nodeEntry);
// 9.9
m_tree.reparent(*node, *lastNode);
// 9.10
lastNode = node;
}
// 10.
- m_tree.insertAlreadyParsedChild(*commonAncestor, *lastNode);
+ m_tree.insertAlreadyParsedChild(commonAncestor.get(), *lastNode);
// 11.
- RefPtr<HTMLStackItem> newItem = m_tree.createElementFromSavedToken(formattingElementRecord->stackItem().get());
- // 12.
- m_tree.takeAllChildren(*newItem, *furthestBlock);
- // 13.
- m_tree.reparent(*furthestBlock, *newItem);
+ auto newItem = m_tree.createElementFromSavedToken(formattingElementRecord->stackItem());
+ // 12. & 13.
+ m_tree.takeAllChildrenAndReparent(newItem, *furthestBlock);
// 14.
- m_tree.activeFormattingElements()->swapTo(formattingElement, newItem, bookmark);
+ m_tree.activeFormattingElements().swapTo(*formattingElement, newItem.copyRef(), bookmark);
// 15.
- m_tree.openElements()->remove(formattingElement);
- m_tree.openElements()->insertAbove(newItem, furthestBlock);
+ m_tree.openElements().remove(*formattingElement);
+ m_tree.openElements().insertAbove(WTFMove(newItem), *furthestBlock);
}
}
@@ -1624,719 +1510,691 @@ void HTMLTreeBuilder::resetInsertionModeAppropriately()
{
// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#reset-the-insertion-mode-appropriately
bool last = false;
- HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord();
- while (1) {
- RefPtr<HTMLStackItem> item = nodeRecord->stackItem();
- if (item->node() == m_tree.openElements()->rootNode()) {
+ for (auto* record = &m_tree.openElements().topRecord(); ; record = record->next()) {
+ HTMLStackItem* item = &record->stackItem();
+ if (&item->node() == &m_tree.openElements().rootNode()) {
last = true;
-#if ENABLE(TEMPLATE_ELEMENT)
bool shouldCreateItem = isParsingFragment();
-#else
- ASSERT(isParsingFragment());
- bool shouldCreateItem = true;
-#endif
if (shouldCreateItem)
- item = HTMLStackItem::create(m_fragmentContext.contextElement(), HTMLStackItem::ItemForContextElement);
+ item = &m_fragmentContext.contextElementStackItem();
}
-#if ENABLE(TEMPLATE_ELEMENT)
- if (item->hasTagName(templateTag))
- return setInsertionMode(m_templateInsertionModes.last());
-#endif
+
+ if (item->hasTagName(templateTag)) {
+ m_insertionMode = m_templateInsertionModes.last();
+ return;
+ }
+
if (item->hasTagName(selectTag)) {
-#if ENABLE(TEMPLATE_ELEMENT)
if (!last) {
- while (item->node() != m_tree.openElements()->rootNode() && !item->hasTagName(templateTag)) {
- nodeRecord = nodeRecord->next();
- item = nodeRecord->stackItem();
- if (isHTMLTableElement(item->node()))
- return setInsertionMode(InsertionMode::InSelectInTable);
+ while (&item->node() != &m_tree.openElements().rootNode() && !item->hasTagName(templateTag)) {
+ record = record->next();
+ item = &record->stackItem();
+ if (is<HTMLTableElement>(item->node())) {
+ m_insertionMode = InsertionMode::InSelectInTable;
+ return;
+ }
}
}
-#endif
- return setInsertionMode(InsertionMode::InSelect);
- }
- if (item->hasTagName(tdTag) || item->hasTagName(thTag))
- return setInsertionMode(InsertionMode::InCell);
- if (item->hasTagName(trTag))
- return setInsertionMode(InsertionMode::InRow);
- if (item->hasTagName(tbodyTag) || item->hasTagName(theadTag) || item->hasTagName(tfootTag))
- return setInsertionMode(InsertionMode::InTableBody);
- if (item->hasTagName(captionTag))
- return setInsertionMode(InsertionMode::InCaption);
+ m_insertionMode = InsertionMode::InSelect;
+ return;
+ }
+ if (item->hasTagName(tdTag) || item->hasTagName(thTag)) {
+ m_insertionMode = InsertionMode::InCell;
+ return;
+ }
+ if (item->hasTagName(trTag)) {
+ m_insertionMode = InsertionMode::InRow;
+ return;
+ }
+ if (item->hasTagName(tbodyTag) || item->hasTagName(theadTag) || item->hasTagName(tfootTag)) {
+ m_insertionMode = InsertionMode::InTableBody;
+ return;
+ }
+ if (item->hasTagName(captionTag)) {
+ m_insertionMode = InsertionMode::InCaption;
+ return;
+ }
if (item->hasTagName(colgroupTag)) {
- return setInsertionMode(InsertionMode::InColumnGroup);
+ m_insertionMode = InsertionMode::InColumnGroup;
+ return;
+ }
+ if (is<HTMLTableElement>(item->node())) {
+ m_insertionMode = InsertionMode::InTable;
+ return;
}
- if (isHTMLTableElement(item->node()))
- return setInsertionMode(InsertionMode::InTable);
if (item->hasTagName(headTag)) {
-#if ENABLE(TEMPLATE_ELEMENT)
- if (!m_fragmentContext.fragment() || m_fragmentContext.contextElement() != item->node())
- return setInsertionMode(InsertionMode::InHead);
-#endif
- return setInsertionMode(InsertionMode::InBody);
+ if (!m_fragmentContext.fragment() || &m_fragmentContext.contextElement() != &item->node()) {
+ m_insertionMode = InsertionMode::InHead;
+ return;
+ }
+ m_insertionMode = InsertionMode::InBody;
+ return;
+ }
+ if (item->hasTagName(bodyTag)) {
+ m_insertionMode = InsertionMode::InBody;
+ return;
}
- if (item->hasTagName(bodyTag))
- return setInsertionMode(InsertionMode::InBody);
if (item->hasTagName(framesetTag)) {
- return setInsertionMode(InsertionMode::InFrameset);
+ m_insertionMode = InsertionMode::InFrameset;
+ return;
}
if (item->hasTagName(htmlTag)) {
- if (m_tree.headStackItem())
- return setInsertionMode(InsertionMode::AfterHead);
+ if (m_tree.headStackItem()) {
+ m_insertionMode = InsertionMode::AfterHead;
+ return;
+ }
ASSERT(isParsingFragment());
- return setInsertionMode(InsertionMode::BeforeHead);
+ m_insertionMode = InsertionMode::BeforeHead;
+ return;
}
if (last) {
ASSERT(isParsingFragment());
- return setInsertionMode(InsertionMode::InBody);
+ m_insertionMode = InsertionMode::InBody;
+ return;
}
- nodeRecord = nodeRecord->next();
}
}
-void HTMLTreeBuilder::processEndTagForInTableBody(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processEndTagForInTableBody(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::EndTag);
- if (isTableBodyContextTag(token->name())) {
- if (!m_tree.openElements()->inTableScope(token->name())) {
+ ASSERT(token.type() == HTMLToken::EndTag);
+ if (isTableBodyContextTag(token.name())) {
+ if (!m_tree.openElements().inTableScope(token.name())) {
parseError(token);
return;
}
- m_tree.openElements()->popUntilTableBodyScopeMarker();
- m_tree.openElements()->pop();
- setInsertionMode(InsertionMode::InTable);
+ m_tree.openElements().popUntilTableBodyScopeMarker();
+ m_tree.openElements().pop();
+ m_insertionMode = InsertionMode::InTable;
return;
}
- if (token->name() == tableTag) {
+ if (token.name() == tableTag) {
// FIXME: This is slow.
- if (!m_tree.openElements()->inTableScope(tbodyTag) && !m_tree.openElements()->inTableScope(theadTag) && !m_tree.openElements()->inTableScope(tfootTag)) {
+ if (!m_tree.openElements().inTableScope(tbodyTag) && !m_tree.openElements().inTableScope(theadTag) && !m_tree.openElements().inTableScope(tfootTag)) {
ASSERT(isParsingFragmentOrTemplateContents());
parseError(token);
return;
}
- m_tree.openElements()->popUntilTableBodyScopeMarker();
- ASSERT(isTableBodyContextTag(m_tree.currentStackItem()->localName()));
- processFakeEndTag(m_tree.currentStackItem()->localName());
- processEndTag(token);
+ m_tree.openElements().popUntilTableBodyScopeMarker();
+ ASSERT(isTableBodyContextTag(m_tree.currentStackItem().localName()));
+ processFakeEndTag(m_tree.currentStackItem().localName());
+ processEndTag(WTFMove(token));
return;
}
- if (token->name() == bodyTag
- || isCaptionColOrColgroupTag(token->name())
- || token->name() == htmlTag
- || isTableCellContextTag(token->name())
- || token->name() == trTag) {
+ if (token.name() == bodyTag
+ || isCaptionColOrColgroupTag(token.name())
+ || token.name() == htmlTag
+ || isTableCellContextTag(token.name())
+ || token.name() == trTag) {
parseError(token);
return;
}
- processEndTagForInTable(token);
+ processEndTagForInTable(WTFMove(token));
}
-void HTMLTreeBuilder::processEndTagForInRow(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processEndTagForInRow(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::EndTag);
- if (token->name() == trTag) {
+ ASSERT(token.type() == HTMLToken::EndTag);
+ if (token.name() == trTag) {
processTrEndTagForInRow();
return;
}
- if (token->name() == tableTag) {
+ if (token.name() == tableTag) {
if (!processTrEndTagForInRow()) {
ASSERT(isParsingFragmentOrTemplateContents());
return;
}
- ASSERT(insertionMode() == InsertionMode::InTableBody);
- processEndTag(token);
+ ASSERT(m_insertionMode == InsertionMode::InTableBody);
+ processEndTag(WTFMove(token));
return;
}
- if (isTableBodyContextTag(token->name())) {
- if (!m_tree.openElements()->inTableScope(token->name())) {
+ if (isTableBodyContextTag(token.name())) {
+ if (!m_tree.openElements().inTableScope(token.name())) {
parseError(token);
return;
}
processFakeEndTag(trTag);
- ASSERT(insertionMode() == InsertionMode::InTableBody);
- processEndTag(token);
+ ASSERT(m_insertionMode == InsertionMode::InTableBody);
+ processEndTag(WTFMove(token));
return;
}
- if (token->name() == bodyTag
- || isCaptionColOrColgroupTag(token->name())
- || token->name() == htmlTag
- || isTableCellContextTag(token->name())) {
+ if (token.name() == bodyTag
+ || isCaptionColOrColgroupTag(token.name())
+ || token.name() == htmlTag
+ || isTableCellContextTag(token.name())) {
parseError(token);
return;
}
- processEndTagForInTable(token);
+ processEndTagForInTable(WTFMove(token));
}
-void HTMLTreeBuilder::processEndTagForInCell(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processEndTagForInCell(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::EndTag);
- if (isTableCellContextTag(token->name())) {
- if (!m_tree.openElements()->inTableScope(token->name())) {
+ ASSERT(token.type() == HTMLToken::EndTag);
+ if (isTableCellContextTag(token.name())) {
+ if (!m_tree.openElements().inTableScope(token.name())) {
parseError(token);
return;
}
m_tree.generateImpliedEndTags();
- if (!m_tree.currentStackItem()->matchesHTMLTag(token->name()))
+ if (!m_tree.currentStackItem().matchesHTMLTag(token.name()))
parseError(token);
- m_tree.openElements()->popUntilPopped(token->name());
- m_tree.activeFormattingElements()->clearToLastMarker();
- setInsertionMode(InsertionMode::InRow);
+ m_tree.openElements().popUntilPopped(token.name());
+ m_tree.activeFormattingElements().clearToLastMarker();
+ m_insertionMode = InsertionMode::InRow;
return;
}
- if (token->name() == bodyTag
- || isCaptionColOrColgroupTag(token->name())
- || token->name() == htmlTag) {
+ if (token.name() == bodyTag
+ || isCaptionColOrColgroupTag(token.name())
+ || token.name() == htmlTag) {
parseError(token);
return;
}
- if (token->name() == tableTag
- || token->name() == trTag
- || isTableBodyContextTag(token->name())) {
- if (!m_tree.openElements()->inTableScope(token->name())) {
-#if ENABLE(TEMPLATE_ELEMENT)
- ASSERT(isTableBodyContextTag(token->name()) || m_tree.openElements()->inTableScope(templateTag) || isParsingFragment());
-#else
- ASSERT(isTableBodyContextTag(token->name()) || isParsingFragment());
-#endif
+ if (token.name() == tableTag
+ || token.name() == trTag
+ || isTableBodyContextTag(token.name())) {
+ if (!m_tree.openElements().inTableScope(token.name())) {
+ ASSERT(isTableBodyContextTag(token.name()) || m_tree.openElements().inTableScope(templateTag) || isParsingFragment());
parseError(token);
return;
}
closeTheCell();
- processEndTag(token);
+ processEndTag(WTFMove(token));
return;
}
- processEndTagForInBody(token);
+ processEndTagForInBody(WTFMove(token));
}
-void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::EndTag);
- if (token->name() == bodyTag) {
- processBodyEndTagForInBody(token);
+ ASSERT(token.type() == HTMLToken::EndTag);
+ if (token.name() == bodyTag) {
+ processBodyEndTagForInBody(WTFMove(token));
return;
}
- if (token->name() == htmlTag) {
+ if (token.name() == htmlTag) {
AtomicHTMLToken endBody(HTMLToken::EndTag, bodyTag.localName());
- if (processBodyEndTagForInBody(&endBody))
- processEndTag(token);
- return;
- }
- if (token->name() == addressTag
- || token->name() == articleTag
- || token->name() == asideTag
- || token->name() == blockquoteTag
- || token->name() == buttonTag
- || token->name() == centerTag
- || token->name() == detailsTag
- || token->name() == dirTag
- || token->name() == divTag
- || token->name() == dlTag
- || token->name() == fieldsetTag
- || token->name() == figcaptionTag
- || token->name() == figureTag
- || token->name() == footerTag
- || token->name() == headerTag
- || token->name() == hgroupTag
- || token->name() == listingTag
- || token->name() == mainTag
- || token->name() == menuTag
- || token->name() == navTag
- || token->name() == olTag
- || token->name() == preTag
- || token->name() == sectionTag
- || token->name() == summaryTag
- || token->name() == ulTag) {
- if (!m_tree.openElements()->inScope(token->name())) {
+ if (processBodyEndTagForInBody(WTFMove(endBody)))
+ processEndTag(WTFMove(token));
+ return;
+ }
+ if (token.name() == addressTag
+ || token.name() == articleTag
+ || token.name() == asideTag
+ || token.name() == blockquoteTag
+ || token.name() == buttonTag
+ || token.name() == centerTag
+ || token.name() == detailsTag
+ || token.name() == dirTag
+ || token.name() == divTag
+ || token.name() == dlTag
+ || token.name() == fieldsetTag
+ || token.name() == figcaptionTag
+ || token.name() == figureTag
+ || token.name() == footerTag
+ || token.name() == headerTag
+ || token.name() == hgroupTag
+ || token.name() == listingTag
+ || token.name() == mainTag
+ || token.name() == menuTag
+ || token.name() == navTag
+ || token.name() == olTag
+ || token.name() == preTag
+ || token.name() == sectionTag
+ || token.name() == summaryTag
+ || token.name() == ulTag) {
+ if (!m_tree.openElements().inScope(token.name())) {
parseError(token);
return;
}
m_tree.generateImpliedEndTags();
- if (!m_tree.currentStackItem()->matchesHTMLTag(token->name()))
+ if (!m_tree.currentStackItem().matchesHTMLTag(token.name()))
parseError(token);
- m_tree.openElements()->popUntilPopped(token->name());
+ m_tree.openElements().popUntilPopped(token.name());
return;
}
- if (token->name() == formTag) {
+ if (token.name() == formTag) {
if (!isParsingTemplateContents()) {
- RefPtr<Element> node = m_tree.takeForm();
- if (!node || !m_tree.openElements()->inScope(node.get())) {
+ RefPtr<Element> formElement = m_tree.takeForm();
+ if (!formElement || !m_tree.openElements().inScope(*formElement)) {
parseError(token);
return;
}
m_tree.generateImpliedEndTags();
- if (m_tree.currentNode() != node.get())
+ if (&m_tree.currentNode() != formElement.get())
parseError(token);
- m_tree.openElements()->remove(node.get());
+ m_tree.openElements().remove(*formElement);
} else {
- if (!m_tree.openElements()->inScope(token->name())) {
+ if (!m_tree.openElements().inScope(token.name())) {
parseError(token);
return;
}
m_tree.generateImpliedEndTags();
- if (!m_tree.currentNode()->hasTagName(formTag))
+ if (!m_tree.currentNode().hasTagName(formTag))
parseError(token);
- m_tree.openElements()->popUntilPopped(token->name());
+ m_tree.openElements().popUntilPopped(token.name());
}
}
- if (token->name() == pTag) {
- if (!m_tree.openElements()->inButtonScope(token->name())) {
+ if (token.name() == pTag) {
+ if (!m_tree.openElements().inButtonScope(token.name())) {
parseError(token);
processFakeStartTag(pTag);
- ASSERT(m_tree.openElements()->inScope(token->name()));
- processEndTag(token);
+ ASSERT(m_tree.openElements().inScope(token.name()));
+ processEndTag(WTFMove(token));
return;
}
- m_tree.generateImpliedEndTagsWithExclusion(token->name());
- if (!m_tree.currentStackItem()->matchesHTMLTag(token->name()))
+ m_tree.generateImpliedEndTagsWithExclusion(token.name());
+ if (!m_tree.currentStackItem().matchesHTMLTag(token.name()))
parseError(token);
- m_tree.openElements()->popUntilPopped(token->name());
+ m_tree.openElements().popUntilPopped(token.name());
return;
}
- if (token->name() == liTag) {
- if (!m_tree.openElements()->inListItemScope(token->name())) {
+ if (token.name() == liTag) {
+ if (!m_tree.openElements().inListItemScope(token.name())) {
parseError(token);
return;
}
- m_tree.generateImpliedEndTagsWithExclusion(token->name());
- if (!m_tree.currentStackItem()->matchesHTMLTag(token->name()))
+ m_tree.generateImpliedEndTagsWithExclusion(token.name());
+ if (!m_tree.currentStackItem().matchesHTMLTag(token.name()))
parseError(token);
- m_tree.openElements()->popUntilPopped(token->name());
+ m_tree.openElements().popUntilPopped(token.name());
return;
}
- if (token->name() == ddTag
- || token->name() == dtTag) {
- if (!m_tree.openElements()->inScope(token->name())) {
+ if (token.name() == ddTag || token.name() == dtTag) {
+ if (!m_tree.openElements().inScope(token.name())) {
parseError(token);
return;
}
- m_tree.generateImpliedEndTagsWithExclusion(token->name());
- if (!m_tree.currentStackItem()->matchesHTMLTag(token->name()))
+ m_tree.generateImpliedEndTagsWithExclusion(token.name());
+ if (!m_tree.currentStackItem().matchesHTMLTag(token.name()))
parseError(token);
- m_tree.openElements()->popUntilPopped(token->name());
+ m_tree.openElements().popUntilPopped(token.name());
return;
}
- if (isNumberedHeaderTag(token->name())) {
- if (!m_tree.openElements()->hasNumberedHeaderElementInScope()) {
+ if (isNumberedHeaderTag(token.name())) {
+ if (!m_tree.openElements().hasNumberedHeaderElementInScope()) {
parseError(token);
return;
}
m_tree.generateImpliedEndTags();
- if (!m_tree.currentStackItem()->matchesHTMLTag(token->name()))
+ if (!m_tree.currentStackItem().matchesHTMLTag(token.name()))
parseError(token);
- m_tree.openElements()->popUntilNumberedHeaderElementPopped();
+ m_tree.openElements().popUntilNumberedHeaderElementPopped();
return;
}
- if (isFormattingTag(token->name())) {
+ if (HTMLConstructionSite::isFormattingTag(token.name())) {
callTheAdoptionAgency(token);
return;
}
- if (token->name() == appletTag
- || token->name() == marqueeTag
- || token->name() == objectTag) {
- if (!m_tree.openElements()->inScope(token->name())) {
+ if (token.name() == appletTag || token.name() == marqueeTag || token.name() == objectTag) {
+ if (!m_tree.openElements().inScope(token.name())) {
parseError(token);
return;
}
m_tree.generateImpliedEndTags();
- if (!m_tree.currentStackItem()->matchesHTMLTag(token->name()))
+ if (!m_tree.currentStackItem().matchesHTMLTag(token.name()))
parseError(token);
- m_tree.openElements()->popUntilPopped(token->name());
- m_tree.activeFormattingElements()->clearToLastMarker();
+ m_tree.openElements().popUntilPopped(token.name());
+ m_tree.activeFormattingElements().clearToLastMarker();
return;
}
- if (token->name() == brTag) {
+ if (token.name() == brTag) {
parseError(token);
processFakeStartTag(brTag);
return;
}
-#if ENABLE(TEMPLATE_ELEMENT)
- if (token->name() == templateTag) {
- processTemplateEndTag(token);
+ if (token.name() == templateTag) {
+ processTemplateEndTag(WTFMove(token));
return;
}
-#endif
- processAnyOtherEndTagForInBody(token);
+ processAnyOtherEndTagForInBody(WTFMove(token));
}
bool HTMLTreeBuilder::processCaptionEndTagForInCaption()
{
- if (!m_tree.openElements()->inTableScope(captionTag.localName())) {
+ if (!m_tree.openElements().inTableScope(captionTag.localName())) {
ASSERT(isParsingFragment());
// FIXME: parse error
return false;
}
m_tree.generateImpliedEndTags();
- // FIXME: parse error if (!m_tree.currentStackItem()->hasTagName(captionTag))
- m_tree.openElements()->popUntilPopped(captionTag.localName());
- m_tree.activeFormattingElements()->clearToLastMarker();
- setInsertionMode(InsertionMode::InTable);
+ // FIXME: parse error if (!m_tree.currentStackItem().hasTagName(captionTag))
+ m_tree.openElements().popUntilPopped(captionTag.localName());
+ m_tree.activeFormattingElements().clearToLastMarker();
+ m_insertionMode = InsertionMode::InTable;
return true;
}
bool HTMLTreeBuilder::processTrEndTagForInRow()
{
- if (!m_tree.openElements()->inTableScope(trTag)) {
+ if (!m_tree.openElements().inTableScope(trTag)) {
ASSERT(isParsingFragmentOrTemplateContents());
// FIXME: parse error
return false;
}
- m_tree.openElements()->popUntilTableRowScopeMarker();
- ASSERT(m_tree.currentStackItem()->hasTagName(trTag));
- m_tree.openElements()->pop();
- setInsertionMode(InsertionMode::InTableBody);
+ m_tree.openElements().popUntilTableRowScopeMarker();
+ ASSERT(m_tree.currentStackItem().hasTagName(trTag));
+ m_tree.openElements().pop();
+ m_insertionMode = InsertionMode::InTableBody;
return true;
}
bool HTMLTreeBuilder::processTableEndTagForInTable()
{
- if (!m_tree.openElements()->inTableScope(tableTag)) {
+ if (!m_tree.openElements().inTableScope(tableTag)) {
ASSERT(isParsingFragmentOrTemplateContents());
// FIXME: parse error.
return false;
}
- m_tree.openElements()->popUntilPopped(tableTag.localName());
+ m_tree.openElements().popUntilPopped(tableTag.localName());
resetInsertionModeAppropriately();
return true;
}
-void HTMLTreeBuilder::processEndTagForInTable(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processEndTagForInTable(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::EndTag);
- if (token->name() == tableTag) {
+ ASSERT(token.type() == HTMLToken::EndTag);
+ if (token.name() == tableTag) {
processTableEndTagForInTable();
return;
}
- if (token->name() == bodyTag
- || isCaptionColOrColgroupTag(token->name())
- || token->name() == htmlTag
- || isTableBodyContextTag(token->name())
- || isTableCellContextTag(token->name())
- || token->name() == trTag) {
+ if (token.name() == bodyTag
+ || isCaptionColOrColgroupTag(token.name())
+ || token.name() == htmlTag
+ || isTableBodyContextTag(token.name())
+ || isTableCellContextTag(token.name())
+ || token.name() == trTag) {
parseError(token);
return;
}
parseError(token);
// Is this redirection necessary here?
HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree);
- processEndTagForInBody(token);
+ processEndTagForInBody(WTFMove(token));
}
-void HTMLTreeBuilder::processEndTag(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processEndTag(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::EndTag);
- switch (insertionMode()) {
+ ASSERT(token.type() == HTMLToken::EndTag);
+ switch (m_insertionMode) {
case InsertionMode::Initial:
- ASSERT(insertionMode() == InsertionMode::Initial);
defaultForInitial();
+ ASSERT(m_insertionMode == InsertionMode::BeforeHTML);
FALLTHROUGH;
case InsertionMode::BeforeHTML:
- ASSERT(insertionMode() == InsertionMode::BeforeHTML);
- if (token->name() != headTag && token->name() != bodyTag && token->name() != htmlTag && token->name() != brTag) {
+ if (token.name() != headTag && token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) {
parseError(token);
return;
}
defaultForBeforeHTML();
+ ASSERT(m_insertionMode == InsertionMode::BeforeHead);
FALLTHROUGH;
case InsertionMode::BeforeHead:
- ASSERT(insertionMode() == InsertionMode::BeforeHead);
- if (token->name() != headTag && token->name() != bodyTag && token->name() != htmlTag && token->name() != brTag) {
+ if (token.name() != headTag && token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) {
parseError(token);
return;
}
defaultForBeforeHead();
+ ASSERT(m_insertionMode == InsertionMode::InHead);
FALLTHROUGH;
case InsertionMode::InHead:
- ASSERT(insertionMode() == InsertionMode::InHead);
// FIXME: This case should be broken out into processEndTagForInHead,
// because other end tag cases now refer to it ("process the token for using the rules of the "in head" insertion mode").
// but because the logic falls through to InsertionMode::AfterHead, that gets a little messy.
-#if ENABLE(TEMPLATE_ELEMENT)
- if (token->name() == templateTag) {
- processTemplateEndTag(token);
+ if (token.name() == templateTag) {
+ processTemplateEndTag(WTFMove(token));
return;
}
-#endif
- if (token->name() == headTag) {
- m_tree.openElements()->popHTMLHeadElement();
- setInsertionMode(InsertionMode::AfterHead);
+ if (token.name() == headTag) {
+ m_tree.openElements().popHTMLHeadElement();
+ m_insertionMode = InsertionMode::AfterHead;
return;
}
- if (token->name() != bodyTag && token->name() != htmlTag && token->name() != brTag) {
+ if (token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) {
parseError(token);
return;
}
defaultForInHead();
+ ASSERT(m_insertionMode == InsertionMode::AfterHead);
FALLTHROUGH;
case InsertionMode::AfterHead:
- ASSERT(insertionMode() == InsertionMode::AfterHead);
- if (token->name() != bodyTag && token->name() != htmlTag && token->name() != brTag) {
+ if (token.name() != bodyTag && token.name() != htmlTag && token.name() != brTag) {
parseError(token);
return;
}
defaultForAfterHead();
+ ASSERT(m_insertionMode == InsertionMode::InBody);
FALLTHROUGH;
case InsertionMode::InBody:
- ASSERT(insertionMode() == InsertionMode::InBody);
- processEndTagForInBody(token);
+ processEndTagForInBody(WTFMove(token));
break;
case InsertionMode::InTable:
- ASSERT(insertionMode() == InsertionMode::InTable);
- processEndTagForInTable(token);
+ processEndTagForInTable(WTFMove(token));
break;
case InsertionMode::InCaption:
- ASSERT(insertionMode() == InsertionMode::InCaption);
- if (token->name() == captionTag) {
+ if (token.name() == captionTag) {
processCaptionEndTagForInCaption();
return;
}
- if (token->name() == tableTag) {
+ if (token.name() == tableTag) {
parseError(token);
if (!processCaptionEndTagForInCaption()) {
ASSERT(isParsingFragment());
return;
}
- processEndTag(token);
+ processEndTag(WTFMove(token));
return;
}
- if (token->name() == bodyTag
- || token->name() == colTag
- || token->name() == colgroupTag
- || token->name() == htmlTag
- || isTableBodyContextTag(token->name())
- || isTableCellContextTag(token->name())
- || token->name() == trTag) {
+ if (token.name() == bodyTag
+ || token.name() == colTag
+ || token.name() == colgroupTag
+ || token.name() == htmlTag
+ || isTableBodyContextTag(token.name())
+ || isTableCellContextTag(token.name())
+ || token.name() == trTag) {
parseError(token);
return;
}
- processEndTagForInBody(token);
+ processEndTagForInBody(WTFMove(token));
break;
case InsertionMode::InColumnGroup:
- ASSERT(insertionMode() == InsertionMode::InColumnGroup);
- if (token->name() == colgroupTag) {
+ if (token.name() == colgroupTag) {
processColgroupEndTagForInColumnGroup();
return;
}
- if (token->name() == colTag) {
+ if (token.name() == colTag) {
parseError(token);
return;
}
-#if ENABLE(TEMPLATE_ELEMENT)
- if (token->name() == templateTag) {
- processTemplateEndTag(token);
+ if (token.name() == templateTag) {
+ processTemplateEndTag(WTFMove(token));
return;
}
-#endif
if (!processColgroupEndTagForInColumnGroup()) {
ASSERT(isParsingFragmentOrTemplateContents());
return;
}
- processEndTag(token);
+ processEndTag(WTFMove(token));
break;
case InsertionMode::InRow:
- ASSERT(insertionMode() == InsertionMode::InRow);
- processEndTagForInRow(token);
+ processEndTagForInRow(WTFMove(token));
break;
case InsertionMode::InCell:
- ASSERT(insertionMode() == InsertionMode::InCell);
- processEndTagForInCell(token);
+ processEndTagForInCell(WTFMove(token));
break;
case InsertionMode::InTableBody:
- ASSERT(insertionMode() == InsertionMode::InTableBody);
- processEndTagForInTableBody(token);
+ processEndTagForInTableBody(WTFMove(token));
break;
case InsertionMode::AfterBody:
- ASSERT(insertionMode() == InsertionMode::AfterBody);
- if (token->name() == htmlTag) {
+ if (token.name() == htmlTag) {
if (isParsingFragment()) {
parseError(token);
return;
}
- setInsertionMode(InsertionMode::AfterAfterBody);
+ m_insertionMode = InsertionMode::AfterAfterBody;
return;
}
FALLTHROUGH;
case InsertionMode::AfterAfterBody:
- ASSERT(insertionMode() == InsertionMode::AfterBody || insertionMode() == InsertionMode::AfterAfterBody);
+ ASSERT(m_insertionMode == InsertionMode::AfterBody || m_insertionMode == InsertionMode::AfterAfterBody);
parseError(token);
- setInsertionMode(InsertionMode::InBody);
- processEndTag(token);
+ m_insertionMode = InsertionMode::InBody;
+ processEndTag(WTFMove(token));
break;
case InsertionMode::InHeadNoscript:
- ASSERT(insertionMode() == InsertionMode::InHeadNoscript);
- if (token->name() == noscriptTag) {
- ASSERT(m_tree.currentStackItem()->hasTagName(noscriptTag));
- m_tree.openElements()->pop();
- ASSERT(m_tree.currentStackItem()->hasTagName(headTag));
- setInsertionMode(InsertionMode::InHead);
+ if (token.name() == noscriptTag) {
+ ASSERT(m_tree.currentStackItem().hasTagName(noscriptTag));
+ m_tree.openElements().pop();
+ ASSERT(m_tree.currentStackItem().hasTagName(headTag));
+ m_insertionMode = InsertionMode::InHead;
return;
}
- if (token->name() != brTag) {
+ if (token.name() != brTag) {
parseError(token);
return;
}
defaultForInHeadNoscript();
- processToken(token);
+ processToken(WTFMove(token));
break;
case InsertionMode::Text:
- if (token->name() == scriptTag) {
+ if (token.name() == scriptTag) {
// Pause ourselves so that parsing stops until the script can be processed by the caller.
- ASSERT(m_tree.currentStackItem()->hasTagName(scriptTag));
+ ASSERT(m_tree.currentStackItem().hasTagName(scriptTag));
if (scriptingContentIsAllowed(m_tree.parserContentPolicy()))
- m_scriptToProcess = m_tree.currentElement();
- m_tree.openElements()->pop();
- setInsertionMode(m_originalInsertionMode);
-
- if (m_parser.tokenizer()) {
- // This token will not have been created by the tokenizer if a
- // self-closing script tag was encountered and pre-HTML5 parser
- // quirks are enabled. We must set the tokenizer's state to
- // DataState explicitly if the tokenizer didn't have a chance to.
- ASSERT(m_parser.tokenizer()->state() == HTMLTokenizer::DataState || m_options.usePreHTML5ParserQuirks);
- m_parser.tokenizer()->setState(HTMLTokenizer::DataState);
- }
+ m_scriptToProcess = &downcast<HTMLScriptElement>(m_tree.currentElement());
+ m_tree.openElements().pop();
+ m_insertionMode = m_originalInsertionMode;
+
+ // This token will not have been created by the tokenizer if a
+ // self-closing script tag was encountered and pre-HTML5 parser
+ // quirks are enabled. We must set the tokenizer's state to
+ // DataState explicitly if the tokenizer didn't have a chance to.
+ ASSERT(m_parser.tokenizer().isInDataState() || m_options.usePreHTML5ParserQuirks);
+ m_parser.tokenizer().setDataState();
return;
}
- m_tree.openElements()->pop();
- setInsertionMode(m_originalInsertionMode);
+ m_tree.openElements().pop();
+ m_insertionMode = m_originalInsertionMode;
break;
case InsertionMode::InFrameset:
- ASSERT(insertionMode() == InsertionMode::InFrameset);
- if (token->name() == framesetTag) {
- bool ignoreFramesetForFragmentParsing = m_tree.currentIsRootNode();
-#if ENABLE(TEMPLATE_ELEMENT)
- ignoreFramesetForFragmentParsing = ignoreFramesetForFragmentParsing || m_tree.openElements()->hasTemplateInHTMLScope();
-#endif
+ if (token.name() == framesetTag) {
+ bool ignoreFramesetForFragmentParsing = m_tree.currentIsRootNode() || m_tree.openElements().hasTemplateInHTMLScope();
if (ignoreFramesetForFragmentParsing) {
ASSERT(isParsingFragmentOrTemplateContents());
parseError(token);
return;
}
- m_tree.openElements()->pop();
- if (!isParsingFragment() && !m_tree.currentStackItem()->hasTagName(framesetTag))
- setInsertionMode(InsertionMode::AfterFrameset);
- return;
- }
-#if ENABLE(TEMPLATE_ELEMENT)
- if (token->name() == templateTag) {
- processTemplateEndTag(token);
+ m_tree.openElements().pop();
+ if (!isParsingFragment() && !m_tree.currentStackItem().hasTagName(framesetTag))
+ m_insertionMode = InsertionMode::AfterFrameset;
return;
}
-#endif
break;
case InsertionMode::AfterFrameset:
- ASSERT(insertionMode() == InsertionMode::AfterFrameset);
- if (token->name() == htmlTag) {
- setInsertionMode(InsertionMode::AfterAfterFrameset);
+ if (token.name() == htmlTag) {
+ m_insertionMode = InsertionMode::AfterAfterFrameset;
return;
}
FALLTHROUGH;
case InsertionMode::AfterAfterFrameset:
- ASSERT(insertionMode() == InsertionMode::AfterFrameset || insertionMode() == InsertionMode::AfterAfterFrameset);
+ ASSERT(m_insertionMode == InsertionMode::AfterFrameset || m_insertionMode == InsertionMode::AfterAfterFrameset);
parseError(token);
break;
case InsertionMode::InSelectInTable:
- ASSERT(insertionMode() == InsertionMode::InSelectInTable);
- if (token->name() == captionTag
- || token->name() == tableTag
- || isTableBodyContextTag(token->name())
- || token->name() == trTag
- || isTableCellContextTag(token->name())) {
+ if (token.name() == captionTag
+ || token.name() == tableTag
+ || isTableBodyContextTag(token.name())
+ || token.name() == trTag
+ || isTableCellContextTag(token.name())) {
parseError(token);
- if (m_tree.openElements()->inTableScope(token->name())) {
+ if (m_tree.openElements().inTableScope(token.name())) {
AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName());
- processEndTag(&endSelect);
- processEndTag(token);
+ processEndTag(WTFMove(endSelect));
+ processEndTag(WTFMove(token));
}
return;
}
FALLTHROUGH;
case InsertionMode::InSelect:
- ASSERT(insertionMode() == InsertionMode::InSelect || insertionMode() == InsertionMode::InSelectInTable);
- if (token->name() == optgroupTag) {
- if (isHTMLOptionElement(m_tree.currentStackItem()->node()) && m_tree.oneBelowTop() && isHTMLOptGroupElement(m_tree.oneBelowTop()->node()))
+ ASSERT(m_insertionMode == InsertionMode::InSelect || m_insertionMode == InsertionMode::InSelectInTable);
+ if (token.name() == optgroupTag) {
+ if (is<HTMLOptionElement>(m_tree.currentStackItem().node()) && m_tree.oneBelowTop() && is<HTMLOptGroupElement>(m_tree.oneBelowTop()->node()))
processFakeEndTag(optionTag);
- if (isHTMLOptGroupElement(m_tree.currentStackItem()->node())) {
- m_tree.openElements()->pop();
+ if (is<HTMLOptGroupElement>(m_tree.currentStackItem().node())) {
+ m_tree.openElements().pop();
return;
}
parseError(token);
return;
}
- if (token->name() == optionTag) {
- if (isHTMLOptionElement(m_tree.currentStackItem()->node())) {
- m_tree.openElements()->pop();
+ if (token.name() == optionTag) {
+ if (is<HTMLOptionElement>(m_tree.currentStackItem().node())) {
+ m_tree.openElements().pop();
return;
}
parseError(token);
return;
}
- if (token->name() == selectTag) {
- if (!m_tree.openElements()->inSelectScope(token->name())) {
+ if (token.name() == selectTag) {
+ if (!m_tree.openElements().inSelectScope(token.name())) {
ASSERT(isParsingFragment());
parseError(token);
return;
}
- m_tree.openElements()->popUntilPopped(selectTag.localName());
+ m_tree.openElements().popUntilPopped(selectTag.localName());
resetInsertionModeAppropriately();
return;
}
-#if ENABLE(TEMPLATE_ELEMENT)
- if (token->name() == templateTag) {
- processTemplateEndTag(token);
+ if (token.name() == templateTag) {
+ processTemplateEndTag(WTFMove(token));
return;
}
-#endif
break;
case InsertionMode::InTableText:
defaultForInTableText();
- processEndTag(token);
+ processEndTag(WTFMove(token));
break;
case InsertionMode::TemplateContents:
-#if ENABLE(TEMPLATE_ELEMENT)
- if (token->name() == templateTag) {
- processTemplateEndTag(token);
+ if (token.name() == templateTag) {
+ processTemplateEndTag(WTFMove(token));
return;
}
-
- break;
-#else
- ASSERT_NOT_REACHED();
-#endif
break;
}
}
-void HTMLTreeBuilder::processComment(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processComment(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::Comment);
+ ASSERT(token.type() == HTMLToken::Comment);
if (m_insertionMode == InsertionMode::Initial
|| m_insertionMode == InsertionMode::BeforeHTML
|| m_insertionMode == InsertionMode::AfterAfterBody
|| m_insertionMode == InsertionMode::AfterAfterFrameset) {
- m_tree.insertCommentOnDocument(token);
+ m_tree.insertCommentOnDocument(WTFMove(token));
return;
}
if (m_insertionMode == InsertionMode::AfterBody) {
- m_tree.insertCommentOnHTMLHtmlElement(token);
+ m_tree.insertCommentOnHTMLHtmlElement(WTFMove(token));
return;
}
if (m_insertionMode == InsertionMode::InTableText) {
defaultForInTableText();
- processComment(token);
+ processComment(WTFMove(token));
return;
}
- m_tree.insertComment(token);
+ m_tree.insertComment(WTFMove(token));
}
-void HTMLTreeBuilder::processCharacter(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processCharacter(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::Character);
+ ASSERT(token.type() == HTMLToken::Character);
ExternalCharacterTokenBuffer buffer(token);
processCharacterBuffer(buffer);
}
+#if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS)
+
// FIXME: Extract the following iOS-specific code into a separate file.
-#if PLATFORM(IOS)
// From the string 4089961010, creates a link of the form <a href="tel:4089961010">4089961010</a> and inserts it.
void HTMLTreeBuilder::insertPhoneNumberLink(const String& string)
{
@@ -2344,13 +2202,13 @@ void HTMLTreeBuilder::insertPhoneNumberLink(const String& string)
attributes.append(Attribute(HTMLNames::hrefAttr, ASCIILiteral("tel:") + string));
const AtomicString& aTagLocalName = aTag.localName();
- AtomicHTMLToken aStartToken(HTMLToken::StartTag, aTagLocalName, attributes);
+ AtomicHTMLToken aStartToken(HTMLToken::StartTag, aTagLocalName, WTFMove(attributes));
AtomicHTMLToken aEndToken(HTMLToken::EndTag, aTagLocalName);
- processStartTag(&aStartToken);
+ processStartTag(WTFMove(aStartToken));
m_tree.executeQueuedTasks();
m_tree.insertTextNode(string);
- processEndTag(&aEndToken);
+ processEndTag(WTFMove(aEndToken));
}
// Locates the phone numbers in the string and deals with it
@@ -2360,13 +2218,7 @@ void HTMLTreeBuilder::insertPhoneNumberLink(const String& string)
// 4. Appends the rest of the string as a text node.
void HTMLTreeBuilder::linkifyPhoneNumbers(const String& string)
{
- static DDDFACacheRef phoneNumbersCache = DDDFACacheCreateFromFramework();
- if (!phoneNumbersCache) {
- m_tree.insertTextNode(string);
- return;
- }
-
- static DDDFAScannerRef phoneNumbersScanner = DDDFAScannerCreateFromCache(phoneNumbersCache);
+ ASSERT(TelephoneNumberDetector::isSupported());
// relativeStartPosition and relativeEndPosition are the endpoints of the phone number range,
// relative to the scannerPosition
@@ -2375,8 +2227,10 @@ void HTMLTreeBuilder::linkifyPhoneNumbers(const String& string)
int relativeStartPosition = 0;
int relativeEndPosition = 0;
+ auto characters = StringView(string).upconvertedCharacters();
+
// While there's a phone number in the rest of the string...
- while ((scannerPosition < length) && DDDFAScannerFirstResultInUnicharArray(phoneNumbersScanner, &string.characters()[scannerPosition], length - scannerPosition, &relativeStartPosition, &relativeEndPosition)) {
+ while (scannerPosition < length && TelephoneNumberDetector::find(&characters[scannerPosition], length - scannerPosition, &relativeStartPosition, &relativeEndPosition)) {
// The convention in the Data Detectors framework is that the end position is the first character NOT in the phone number
// (that is, the length of the range is relativeEndPosition - relativeStartPosition). So substract 1 to get the same
// convention as the old WebCore phone number parser (so that the rest of the code is still valid if we want to go back
@@ -2402,12 +2256,11 @@ void HTMLTreeBuilder::linkifyPhoneNumbers(const String& string)
}
// Looks at the ancestors of the element to determine whether we're inside an element which disallows parsing phone numbers.
-static inline bool disallowTelephoneNumberParsing(const Node& node)
+static inline bool disallowTelephoneNumberParsing(const ContainerNode& node)
{
return node.isLink()
- || node.nodeType() == Node::COMMENT_NODE
|| node.hasTagName(scriptTag)
- || (node.isHTMLElement() && toHTMLElement(node).isFormControlElement())
+ || is<HTMLFormControlElement>(node)
|| node.hasTagName(styleTag)
|| node.hasTagName(ttTag)
|| node.hasTagName(preTag)
@@ -2416,15 +2269,14 @@ static inline bool disallowTelephoneNumberParsing(const Node& node)
static inline bool shouldParseTelephoneNumbersInNode(const ContainerNode& node)
{
- const ContainerNode* currentNode = &node;
- do {
- if (currentNode->isElementNode() && disallowTelephoneNumberParsing(*currentNode))
+ for (const ContainerNode* ancestor = &node; ancestor; ancestor = ancestor->parentNode()) {
+ if (disallowTelephoneNumberParsing(*ancestor))
return false;
- currentNode = currentNode->parentNode();
- } while (currentNode);
+ }
return true;
}
-#endif // PLATFORM(IOS)
+
+#endif // ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS)
void HTMLTreeBuilder::processCharacterBuffer(ExternalCharacterTokenBuffer& buffer)
{
@@ -2447,77 +2299,66 @@ ReprocessBuffer:
return;
}
- switch (insertionMode()) {
- case InsertionMode::Initial: {
- ASSERT(insertionMode() == InsertionMode::Initial);
+ switch (m_insertionMode) {
+ case InsertionMode::Initial:
buffer.skipLeadingWhitespace();
if (buffer.isEmpty())
return;
defaultForInitial();
+ ASSERT(m_insertionMode == InsertionMode::BeforeHTML);
FALLTHROUGH;
- }
- case InsertionMode::BeforeHTML: {
- ASSERT(insertionMode() == InsertionMode::BeforeHTML);
+ case InsertionMode::BeforeHTML:
buffer.skipLeadingWhitespace();
if (buffer.isEmpty())
return;
defaultForBeforeHTML();
+ ASSERT(m_insertionMode == InsertionMode::BeforeHead);
FALLTHROUGH;
- }
- case InsertionMode::BeforeHead: {
- ASSERT(insertionMode() == InsertionMode::BeforeHead);
+ case InsertionMode::BeforeHead:
buffer.skipLeadingWhitespace();
if (buffer.isEmpty())
return;
defaultForBeforeHead();
+ ASSERT(m_insertionMode == InsertionMode::InHead);
FALLTHROUGH;
- }
case InsertionMode::InHead: {
- ASSERT(insertionMode() == InsertionMode::InHead);
String leadingWhitespace = buffer.takeLeadingWhitespace();
if (!leadingWhitespace.isEmpty())
m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
if (buffer.isEmpty())
return;
defaultForInHead();
+ ASSERT(m_insertionMode == InsertionMode::AfterHead);
FALLTHROUGH;
}
case InsertionMode::AfterHead: {
- ASSERT(insertionMode() == InsertionMode::AfterHead);
String leadingWhitespace = buffer.takeLeadingWhitespace();
if (!leadingWhitespace.isEmpty())
m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
if (buffer.isEmpty())
return;
defaultForAfterHead();
+ ASSERT(m_insertionMode == InsertionMode::InBody);
FALLTHROUGH;
}
case InsertionMode::InBody:
case InsertionMode::InCaption:
+ case InsertionMode::InCell:
case InsertionMode::TemplateContents:
- case InsertionMode::InCell: {
-#if ENABLE(TEMPLATE_ELEMENT)
- ASSERT(insertionMode() == InsertionMode::InBody || insertionMode() == InsertionMode::InCaption || insertionMode() == InsertionMode::InCell || insertionMode() == InsertionMode::TemplateContents);
-#else
- ASSERT(insertionMode() != InsertionMode::TemplateContents);
- ASSERT(insertionMode() == InsertionMode::InBody || insertionMode() == InsertionMode::InCaption || insertionMode() == InsertionMode::InCell);
-#endif
processCharacterBufferForInBody(buffer);
break;
- }
case InsertionMode::InTable:
case InsertionMode::InTableBody:
- case InsertionMode::InRow: {
- ASSERT(insertionMode() == InsertionMode::InTable || insertionMode() == InsertionMode::InTableBody || insertionMode() == InsertionMode::InRow);
+ case InsertionMode::InRow:
ASSERT(m_pendingTableCharacters.isEmpty());
- if (m_tree.currentStackItem()->isElementNode()
- && (isHTMLTableElement(m_tree.currentStackItem()->node())
- || m_tree.currentStackItem()->hasTagName(HTMLNames::tbodyTag)
- || m_tree.currentStackItem()->hasTagName(HTMLNames::tfootTag)
- || m_tree.currentStackItem()->hasTagName(HTMLNames::theadTag)
- || m_tree.currentStackItem()->hasTagName(HTMLNames::trTag))) {
+ if (is<HTMLTableElement>(m_tree.currentStackItem().node())
+ || m_tree.currentStackItem().hasTagName(HTMLNames::tbodyTag)
+ || m_tree.currentStackItem().hasTagName(HTMLNames::tfootTag)
+ || m_tree.currentStackItem().hasTagName(HTMLNames::theadTag)
+ || m_tree.currentStackItem().hasTagName(HTMLNames::trTag)) {
+
m_originalInsertionMode = m_insertionMode;
- setInsertionMode(InsertionMode::InTableText);
+ m_insertionMode = InsertionMode::InTableText;
// Note that we fall through to the InsertionMode::InTableText case below.
} else {
HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree);
@@ -2525,13 +2366,10 @@ ReprocessBuffer:
break;
}
FALLTHROUGH;
- }
- case InsertionMode::InTableText: {
+ case InsertionMode::InTableText:
buffer.giveRemainingTo(m_pendingTableCharacters);
break;
- }
case InsertionMode::InColumnGroup: {
- ASSERT(insertionMode() == InsertionMode::InColumnGroup);
String leadingWhitespace = buffer.takeLeadingWhitespace();
if (!leadingWhitespace.isEmpty())
m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
@@ -2547,20 +2385,14 @@ ReprocessBuffer:
goto ReprocessBuffer;
}
case InsertionMode::AfterBody:
- case InsertionMode::AfterAfterBody: {
- ASSERT(insertionMode() == InsertionMode::AfterBody || insertionMode() == InsertionMode::AfterAfterBody);
+ case InsertionMode::AfterAfterBody:
// FIXME: parse error
- setInsertionMode(InsertionMode::InBody);
+ m_insertionMode = InsertionMode::InBody;
goto ReprocessBuffer;
- break;
- }
- case InsertionMode::Text: {
- ASSERT(insertionMode() == InsertionMode::Text);
+ case InsertionMode::Text:
m_tree.insertTextNode(buffer.takeRemaining());
break;
- }
case InsertionMode::InHeadNoscript: {
- ASSERT(insertionMode() == InsertionMode::InHeadNoscript);
String leadingWhitespace = buffer.takeLeadingWhitespace();
if (!leadingWhitespace.isEmpty())
m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
@@ -2568,11 +2400,9 @@ ReprocessBuffer:
return;
defaultForInHeadNoscript();
goto ReprocessBuffer;
- break;
}
case InsertionMode::InFrameset:
case InsertionMode::AfterFrameset: {
- ASSERT(insertionMode() == InsertionMode::InFrameset || insertionMode() == InsertionMode::AfterFrameset || insertionMode() == InsertionMode::AfterAfterFrameset);
String leadingWhitespace = buffer.takeRemainingWhitespace();
if (!leadingWhitespace.isEmpty())
m_tree.insertTextNode(leadingWhitespace, AllWhitespace);
@@ -2581,11 +2411,9 @@ ReprocessBuffer:
break;
}
case InsertionMode::InSelectInTable:
- case InsertionMode::InSelect: {
- ASSERT(insertionMode() == InsertionMode::InSelect || insertionMode() == InsertionMode::InSelectInTable);
+ case InsertionMode::InSelect:
m_tree.insertTextNode(buffer.takeRemaining());
break;
- }
case InsertionMode::AfterAfterFrameset: {
String leadingWhitespace = buffer.takeRemainingWhitespace();
if (!leadingWhitespace.isEmpty()) {
@@ -2603,83 +2431,68 @@ void HTMLTreeBuilder::processCharacterBufferForInBody(ExternalCharacterTokenBuff
{
m_tree.reconstructTheActiveFormattingElements();
String characters = buffer.takeRemaining();
-#if PLATFORM(IOS)
- if (!isParsingFragment() && m_tree.isTelephoneNumberParsingEnabled() && shouldParseTelephoneNumbersInNode(*m_tree.currentNode()) && DataDetectorsCoreLibrary())
+#if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS)
+ if (!isParsingFragment() && m_tree.isTelephoneNumberParsingEnabled() && shouldParseTelephoneNumbersInNode(m_tree.currentNode()) && TelephoneNumberDetector::isSupported())
linkifyPhoneNumbers(characters);
else
m_tree.insertTextNode(characters);
#else
m_tree.insertTextNode(characters);
#endif
-
if (m_framesetOk && !isAllWhitespaceOrReplacementCharacters(characters))
m_framesetOk = false;
}
-void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::EndOfFile);
- switch (insertionMode()) {
+ ASSERT(token.type() == HTMLToken::EndOfFile);
+ switch (m_insertionMode) {
case InsertionMode::Initial:
- ASSERT(insertionMode() == InsertionMode::Initial);
defaultForInitial();
+ ASSERT(m_insertionMode == InsertionMode::BeforeHTML);
FALLTHROUGH;
case InsertionMode::BeforeHTML:
- ASSERT(insertionMode() == InsertionMode::BeforeHTML);
defaultForBeforeHTML();
+ ASSERT(m_insertionMode == InsertionMode::BeforeHead);
FALLTHROUGH;
case InsertionMode::BeforeHead:
- ASSERT(insertionMode() == InsertionMode::BeforeHead);
defaultForBeforeHead();
+ ASSERT(m_insertionMode == InsertionMode::InHead);
FALLTHROUGH;
case InsertionMode::InHead:
- ASSERT(insertionMode() == InsertionMode::InHead);
defaultForInHead();
+ ASSERT(m_insertionMode == InsertionMode::AfterHead);
FALLTHROUGH;
case InsertionMode::AfterHead:
- ASSERT(insertionMode() == InsertionMode::AfterHead);
defaultForAfterHead();
+ ASSERT(m_insertionMode == InsertionMode::InBody);
FALLTHROUGH;
case InsertionMode::InBody:
case InsertionMode::InCell:
case InsertionMode::InCaption:
case InsertionMode::InRow:
-#if ENABLE(TEMPLATE_ELEMENT)
- ASSERT(insertionMode() == InsertionMode::InBody || insertionMode() == InsertionMode::InCell || insertionMode() == InsertionMode::InCaption || insertionMode() == InsertionMode::InRow || insertionMode() == InsertionMode::TemplateContents);
-#else
- ASSERT(insertionMode() != InsertionMode::TemplateContents);
- ASSERT(insertionMode() == InsertionMode::InBody || insertionMode() == InsertionMode::InCell || insertionMode() == InsertionMode::InCaption || insertionMode() == InsertionMode::InRow);
-#endif
notImplemented(); // Emit parse error based on what elements are still open.
-#if ENABLE(TEMPLATE_ELEMENT)
- if (!m_templateInsertionModes.isEmpty())
- if (processEndOfFileForInTemplateContents(token))
+ if (!m_templateInsertionModes.isEmpty()) {
+ if (processEndOfFileForInTemplateContents(WTFMove(token)))
return;
-#endif
+ }
break;
case InsertionMode::AfterBody:
case InsertionMode::AfterAfterBody:
- ASSERT(insertionMode() == InsertionMode::AfterBody || insertionMode() == InsertionMode::AfterAfterBody);
break;
case InsertionMode::InHeadNoscript:
- ASSERT(insertionMode() == InsertionMode::InHeadNoscript);
defaultForInHeadNoscript();
- processEndOfFile(token);
+ processEndOfFile(WTFMove(token));
return;
case InsertionMode::AfterFrameset:
case InsertionMode::AfterAfterFrameset:
- ASSERT(insertionMode() == InsertionMode::AfterFrameset || insertionMode() == InsertionMode::AfterAfterFrameset);
break;
case InsertionMode::InColumnGroup:
if (m_tree.currentIsRootNode()) {
ASSERT(isParsingFragment());
return; // FIXME: Should we break here instead of returning?
}
-#if ENABLE(TEMPLATE_ELEMENT)
- ASSERT(m_tree.currentNode()->hasTagName(colgroupTag) || m_tree.currentNode()->hasTagName(templateTag));
-#else
- ASSERT(m_tree.currentNode()->hasTagName(colgroupTag));
-#endif
+ ASSERT(m_tree.currentNode().hasTagName(colgroupTag) || m_tree.currentNode().hasTagName(templateTag));
processColgroupEndTagForInColumnGroup();
FALLTHROUGH;
case InsertionMode::InFrameset:
@@ -2687,40 +2500,33 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken* token)
case InsertionMode::InTableBody:
case InsertionMode::InSelectInTable:
case InsertionMode::InSelect:
- ASSERT(insertionMode() == InsertionMode::InSelect || insertionMode() == InsertionMode::InSelectInTable || insertionMode() == InsertionMode::InTable || insertionMode() == InsertionMode::InFrameset || insertionMode() == InsertionMode::InTableBody || insertionMode() == InsertionMode::InColumnGroup);
- if (m_tree.currentNode() != m_tree.openElements()->rootNode())
+ ASSERT(m_insertionMode == InsertionMode::InSelect || m_insertionMode == InsertionMode::InSelectInTable || m_insertionMode == InsertionMode::InTable || m_insertionMode == InsertionMode::InFrameset || m_insertionMode == InsertionMode::InTableBody || m_insertionMode == InsertionMode::InColumnGroup);
+ if (&m_tree.currentNode() != &m_tree.openElements().rootNode())
parseError(token);
-
-#if ENABLE(TEMPLATE_ELEMENT)
- if (!m_templateInsertionModes.isEmpty())
- if (processEndOfFileForInTemplateContents(token))
+ if (!m_templateInsertionModes.isEmpty()) {
+ if (processEndOfFileForInTemplateContents(WTFMove(token)))
return;
-#endif
+ }
break;
case InsertionMode::InTableText:
defaultForInTableText();
- processEndOfFile(token);
+ processEndOfFile(WTFMove(token));
return;
case InsertionMode::Text:
parseError(token);
- if (m_tree.currentStackItem()->hasTagName(scriptTag))
+ if (m_tree.currentStackItem().hasTagName(scriptTag))
notImplemented(); // mark the script element as "already started".
- m_tree.openElements()->pop();
+ m_tree.openElements().pop();
ASSERT(m_originalInsertionMode != InsertionMode::Text);
- setInsertionMode(m_originalInsertionMode);
- processEndOfFile(token);
+ m_insertionMode = m_originalInsertionMode;
+ processEndOfFile(WTFMove(token));
return;
case InsertionMode::TemplateContents:
-#if ENABLE(TEMPLATE_ELEMENT)
- if (processEndOfFileForInTemplateContents(token))
+ if (processEndOfFileForInTemplateContents(WTFMove(token)))
return;
break;
-#else
- ASSERT_NOT_REACHED();
-#endif
}
- ASSERT(m_tree.currentNode());
- m_tree.openElements()->popAll();
+ m_tree.openElements().popAll();
}
void HTMLTreeBuilder::defaultForInitial()
@@ -2728,38 +2534,38 @@ void HTMLTreeBuilder::defaultForInitial()
notImplemented();
m_tree.setDefaultCompatibilityMode();
// FIXME: parse error
- setInsertionMode(InsertionMode::BeforeHTML);
+ m_insertionMode = InsertionMode::BeforeHTML;
}
void HTMLTreeBuilder::defaultForBeforeHTML()
{
AtomicHTMLToken startHTML(HTMLToken::StartTag, htmlTag.localName());
- m_tree.insertHTMLHtmlStartTagBeforeHTML(&startHTML);
- setInsertionMode(InsertionMode::BeforeHead);
+ m_tree.insertHTMLHtmlStartTagBeforeHTML(WTFMove(startHTML));
+ m_insertionMode = InsertionMode::BeforeHead;
}
void HTMLTreeBuilder::defaultForBeforeHead()
{
AtomicHTMLToken startHead(HTMLToken::StartTag, headTag.localName());
- processStartTag(&startHead);
+ processStartTag(WTFMove(startHead));
}
void HTMLTreeBuilder::defaultForInHead()
{
AtomicHTMLToken endHead(HTMLToken::EndTag, headTag.localName());
- processEndTag(&endHead);
+ processEndTag(WTFMove(endHead));
}
void HTMLTreeBuilder::defaultForInHeadNoscript()
{
AtomicHTMLToken endNoscript(HTMLToken::EndTag, noscriptTag.localName());
- processEndTag(&endNoscript);
+ processEndTag(WTFMove(endNoscript));
}
void HTMLTreeBuilder::defaultForAfterHead()
{
AtomicHTMLToken startBody(HTMLToken::StartTag, bodyTag.localName());
- processStartTag(&startBody);
+ processStartTag(WTFMove(startBody));
m_framesetOk = true;
}
@@ -2773,135 +2579,149 @@ void HTMLTreeBuilder::defaultForInTableText()
m_tree.reconstructTheActiveFormattingElements();
m_tree.insertTextNode(characters, NotAllWhitespace);
m_framesetOk = false;
- setInsertionMode(m_originalInsertionMode);
+ m_insertionMode = m_originalInsertionMode;
return;
}
m_tree.insertTextNode(characters);
- setInsertionMode(m_originalInsertionMode);
+ m_insertionMode = m_originalInsertionMode;
}
-bool HTMLTreeBuilder::processStartTagForInHead(AtomicHTMLToken* token)
+bool HTMLTreeBuilder::processStartTagForInHead(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::StartTag);
- if (token->name() == htmlTag) {
- processHtmlStartTagForInBody(token);
+ ASSERT(token.type() == HTMLToken::StartTag);
+ if (token.name() == htmlTag) {
+ processHtmlStartTagForInBody(WTFMove(token));
return true;
}
- if (token->name() == baseTag
- || token->name() == basefontTag
- || token->name() == bgsoundTag
- || token->name() == commandTag
- || token->name() == linkTag
- || token->name() == metaTag) {
- m_tree.insertSelfClosingHTMLElement(token);
+ if (token.name() == baseTag
+ || token.name() == basefontTag
+ || token.name() == bgsoundTag
+ || token.name() == commandTag
+ || token.name() == linkTag
+ || token.name() == metaTag) {
+ m_tree.insertSelfClosingHTMLElement(WTFMove(token));
// Note: The custom processing for the <meta> tag is done in HTMLMetaElement::process().
return true;
}
- if (token->name() == titleTag) {
- processGenericRCDATAStartTag(token);
+ if (token.name() == titleTag) {
+ processGenericRCDATAStartTag(WTFMove(token));
return true;
}
- if (token->name() == noscriptTag) {
+ if (token.name() == noscriptTag) {
if (m_options.scriptEnabled) {
- processGenericRawTextStartTag(token);
+ processGenericRawTextStartTag(WTFMove(token));
return true;
}
- m_tree.insertHTMLElement(token);
- setInsertionMode(InsertionMode::InHeadNoscript);
+ m_tree.insertHTMLElement(WTFMove(token));
+ m_insertionMode = InsertionMode::InHeadNoscript;
return true;
}
- if (token->name() == noframesTag || token->name() == styleTag) {
- processGenericRawTextStartTag(token);
+ if (token.name() == noframesTag || token.name() == styleTag) {
+ processGenericRawTextStartTag(WTFMove(token));
return true;
}
- if (token->name() == scriptTag) {
- processScriptStartTag(token);
- if (m_options.usePreHTML5ParserQuirks && token->selfClosing())
+ if (token.name() == scriptTag) {
+ bool isSelfClosing = token.selfClosing();
+ processScriptStartTag(WTFMove(token));
+ if (m_options.usePreHTML5ParserQuirks && isSelfClosing)
processFakeEndTag(scriptTag);
return true;
}
-#if ENABLE(TEMPLATE_ELEMENT)
- if (token->name() == templateTag) {
- processTemplateStartTag(token);
+ if (token.name() == templateTag) {
+ m_framesetOk = false;
+ processTemplateStartTag(WTFMove(token));
return true;
}
-#endif
- if (token->name() == headTag) {
+ if (token.name() == headTag) {
parseError(token);
return true;
}
return false;
}
-void HTMLTreeBuilder::processGenericRCDATAStartTag(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processGenericRCDATAStartTag(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::StartTag);
- m_tree.insertHTMLElement(token);
- if (m_parser.tokenizer())
- m_parser.tokenizer()->setState(HTMLTokenizer::RCDATAState);
+ ASSERT(token.type() == HTMLToken::StartTag);
+ m_tree.insertHTMLElement(WTFMove(token));
+ m_parser.tokenizer().setRCDATAState();
m_originalInsertionMode = m_insertionMode;
- setInsertionMode(InsertionMode::Text);
+ m_insertionMode = InsertionMode::Text;
}
-void HTMLTreeBuilder::processGenericRawTextStartTag(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processGenericRawTextStartTag(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::StartTag);
- m_tree.insertHTMLElement(token);
- if (m_parser.tokenizer())
- m_parser.tokenizer()->setState(HTMLTokenizer::RAWTEXTState);
+ ASSERT(token.type() == HTMLToken::StartTag);
+ m_tree.insertHTMLElement(WTFMove(token));
+ m_parser.tokenizer().setRAWTEXTState();
m_originalInsertionMode = m_insertionMode;
- setInsertionMode(InsertionMode::Text);
+ m_insertionMode = InsertionMode::Text;
}
-void HTMLTreeBuilder::processScriptStartTag(AtomicHTMLToken* token)
+void HTMLTreeBuilder::processScriptStartTag(AtomicHTMLToken&& token)
{
- ASSERT(token->type() == HTMLToken::StartTag);
- m_tree.insertScriptElement(token);
- if (m_parser.tokenizer())
- m_parser.tokenizer()->setState(HTMLTokenizer::ScriptDataState);
+ ASSERT(token.type() == HTMLToken::StartTag);
+ m_tree.insertScriptElement(WTFMove(token));
+ m_parser.tokenizer().setScriptDataState();
m_originalInsertionMode = m_insertionMode;
TextPosition position = m_parser.textPosition();
m_scriptToProcessStartPosition = position;
- setInsertionMode(InsertionMode::Text);
+ m_insertionMode = InsertionMode::Text;
+}
+
+// http://www.whatwg.org/specs/web-apps/current-work/#adjusted-current-node
+HTMLStackItem& HTMLTreeBuilder::adjustedCurrentStackItem() const
+{
+ ASSERT(!m_tree.isEmpty());
+ if (isParsingFragment() && m_tree.openElements().hasOnlyOneElement())
+ return m_fragmentContext.contextElementStackItem();
+
+ return m_tree.currentStackItem();
}
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#tree-construction
-bool HTMLTreeBuilder::shouldProcessTokenInForeignContent(AtomicHTMLToken* token)
+bool HTMLTreeBuilder::shouldProcessTokenInForeignContent(const AtomicHTMLToken& token)
{
if (m_tree.isEmpty())
return false;
- HTMLStackItem* item = m_tree.currentStackItem();
- if (item->isInHTMLNamespace())
+ HTMLStackItem& adjustedCurrentNode = adjustedCurrentStackItem();
+ if (isInHTMLNamespace(adjustedCurrentNode))
return false;
- if (HTMLElementStack::isMathMLTextIntegrationPoint(item)) {
- if (token->type() == HTMLToken::StartTag
- && token->name() != MathMLNames::mglyphTag
- && token->name() != MathMLNames::malignmarkTag)
+ if (HTMLElementStack::isMathMLTextIntegrationPoint(adjustedCurrentNode)) {
+ if (token.type() == HTMLToken::StartTag
+ && token.name() != MathMLNames::mglyphTag
+ && token.name() != MathMLNames::malignmarkTag)
return false;
- if (token->type() == HTMLToken::Character)
+ if (token.type() == HTMLToken::Character)
return false;
}
- if (item->hasTagName(MathMLNames::annotation_xmlTag)
- && token->type() == HTMLToken::StartTag
- && token->name() == SVGNames::svgTag)
+ if (adjustedCurrentNode.hasTagName(MathMLNames::annotation_xmlTag)
+ && token.type() == HTMLToken::StartTag
+ && token.name() == SVGNames::svgTag)
return false;
- if (HTMLElementStack::isHTMLIntegrationPoint(item)) {
- if (token->type() == HTMLToken::StartTag)
+ if (HTMLElementStack::isHTMLIntegrationPoint(adjustedCurrentNode)) {
+ if (token.type() == HTMLToken::StartTag)
return false;
- if (token->type() == HTMLToken::Character)
+ if (token.type() == HTMLToken::Character)
return false;
}
- if (token->type() == HTMLToken::EndOfFile)
+ if (token.type() == HTMLToken::EndOfFile)
return false;
return true;
}
-void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken* token)
+static bool hasAttribute(const AtomicHTMLToken& token, const QualifiedName& name)
+{
+ return findAttribute(token.attributes(), name);
+}
+
+void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken&& token)
{
- switch (token->type()) {
+ HTMLStackItem& adjustedCurrentNode = adjustedCurrentStackItem();
+
+ switch (token.type()) {
case HTMLToken::Uninitialized:
ASSERT_NOT_REACHED();
break;
@@ -2909,52 +2729,52 @@ void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken* token)
parseError(token);
break;
case HTMLToken::StartTag: {
- if (token->name() == bTag
- || token->name() == bigTag
- || token->name() == blockquoteTag
- || token->name() == bodyTag
- || token->name() == brTag
- || token->name() == centerTag
- || token->name() == codeTag
- || token->name() == ddTag
- || token->name() == divTag
- || token->name() == dlTag
- || token->name() == dtTag
- || token->name() == emTag
- || token->name() == embedTag
- || isNumberedHeaderTag(token->name())
- || token->name() == headTag
- || token->name() == hrTag
- || token->name() == iTag
- || token->name() == imgTag
- || token->name() == liTag
- || token->name() == listingTag
- || token->name() == menuTag
- || token->name() == metaTag
- || token->name() == nobrTag
- || token->name() == olTag
- || token->name() == pTag
- || token->name() == preTag
- || token->name() == rubyTag
- || token->name() == sTag
- || token->name() == smallTag
- || token->name() == spanTag
- || token->name() == strongTag
- || token->name() == strikeTag
- || token->name() == subTag
- || token->name() == supTag
- || token->name() == tableTag
- || token->name() == ttTag
- || token->name() == uTag
- || token->name() == ulTag
- || token->name() == varTag
- || (token->name() == fontTag && (token->getAttributeItem(colorAttr) || token->getAttributeItem(faceAttr) || token->getAttributeItem(sizeAttr)))) {
+ if (token.name() == bTag
+ || token.name() == bigTag
+ || token.name() == blockquoteTag
+ || token.name() == bodyTag
+ || token.name() == brTag
+ || token.name() == centerTag
+ || token.name() == codeTag
+ || token.name() == ddTag
+ || token.name() == divTag
+ || token.name() == dlTag
+ || token.name() == dtTag
+ || token.name() == emTag
+ || token.name() == embedTag
+ || isNumberedHeaderTag(token.name())
+ || token.name() == headTag
+ || token.name() == hrTag
+ || token.name() == iTag
+ || token.name() == imgTag
+ || token.name() == liTag
+ || token.name() == listingTag
+ || token.name() == menuTag
+ || token.name() == metaTag
+ || token.name() == nobrTag
+ || token.name() == olTag
+ || token.name() == pTag
+ || token.name() == preTag
+ || token.name() == rubyTag
+ || token.name() == sTag
+ || token.name() == smallTag
+ || token.name() == spanTag
+ || token.name() == strongTag
+ || token.name() == strikeTag
+ || token.name() == subTag
+ || token.name() == supTag
+ || token.name() == tableTag
+ || token.name() == ttTag
+ || token.name() == uTag
+ || token.name() == ulTag
+ || token.name() == varTag
+ || (token.name() == fontTag && (hasAttribute(token, colorAttr) || hasAttribute(token, faceAttr) || hasAttribute(token, sizeAttr)))) {
parseError(token);
- m_tree.openElements()->popUntilForeignContentScopeMarker();
- processStartTag(token);
+ m_tree.openElements().popUntilForeignContentScopeMarker();
+ processStartTag(WTFMove(token));
return;
}
- const AtomicString& currentNamespace = m_tree.currentStackItem()->namespaceURI();
+ const AtomicString& currentNamespace = adjustedCurrentNode.namespaceURI();
if (currentNamespace == MathMLNames::mathmlNamespaceURI)
adjustMathMLAttributes(token);
if (currentNamespace == SVGNames::svgNamespaceURI) {
@@ -2962,44 +2782,44 @@ void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken* token)
adjustSVGAttributes(token);
}
adjustForeignAttributes(token);
- m_tree.insertForeignElement(token, currentNamespace);
+ m_tree.insertForeignElement(WTFMove(token), currentNamespace);
break;
}
case HTMLToken::EndTag: {
- if (m_tree.currentStackItem()->namespaceURI() == SVGNames::svgNamespaceURI)
+ if (adjustedCurrentNode.namespaceURI() == SVGNames::svgNamespaceURI)
adjustSVGTagNameCase(token);
- if (token->name() == SVGNames::scriptTag && m_tree.currentStackItem()->hasTagName(SVGNames::scriptTag)) {
+ if (token.name() == SVGNames::scriptTag && m_tree.currentStackItem().hasTagName(SVGNames::scriptTag)) {
if (scriptingContentIsAllowed(m_tree.parserContentPolicy()))
- m_scriptToProcess = m_tree.currentElement();
- m_tree.openElements()->pop();
+ m_scriptToProcess = &downcast<SVGScriptElement>(m_tree.currentElement());
+ m_tree.openElements().pop();
return;
}
- if (!m_tree.currentStackItem()->isInHTMLNamespace()) {
+ if (!isInHTMLNamespace(m_tree.currentStackItem())) {
// FIXME: This code just wants an Element* iterator, instead of an ElementRecord*
- HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord();
- if (!nodeRecord->stackItem()->hasLocalName(token->name()))
+ auto* nodeRecord = &m_tree.openElements().topRecord();
+ if (nodeRecord->stackItem().localName() != token.name())
parseError(token);
while (1) {
- if (nodeRecord->stackItem()->hasLocalName(token->name())) {
- m_tree.openElements()->popUntilPopped(nodeRecord->element());
+ if (nodeRecord->stackItem().localName() == token.name()) {
+ m_tree.openElements().popUntilPopped(nodeRecord->element());
return;
}
nodeRecord = nodeRecord->next();
- if (nodeRecord->stackItem()->isInHTMLNamespace())
+ if (isInHTMLNamespace(nodeRecord->stackItem()))
break;
}
}
// Otherwise, process the token according to the rules given in the section corresponding to the current insertion mode in HTML content.
- processEndTag(token);
+ processEndTag(WTFMove(token));
break;
}
case HTMLToken::Comment:
- m_tree.insertComment(token);
+ m_tree.insertComment(WTFMove(token));
return;
case HTMLToken::Character: {
- String characters = String(token->characters(), token->charactersLength());
+ String characters = String(token.characters(), token.charactersLength());
m_tree.insertTextNode(characters);
if (m_framesetOk && !isAllWhitespaceOrReplacementCharacters(characters))
m_framesetOk = false;
@@ -3013,19 +2833,18 @@ void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken* token)
void HTMLTreeBuilder::finished()
{
+ ASSERT(!m_destroyed);
+
if (isParsingFragment())
return;
-#if ENABLE(TEMPLATE_ELEMENT)
ASSERT(m_templateInsertionModes.isEmpty());
-#endif
- ASSERT(m_isAttached);
- // Warning, this may detach the parser. Do not do anything else after this.
m_tree.finishedParsing();
+ // The tree builder might have been destroyed as an indirect result of finishing the parsing.
}
-void HTMLTreeBuilder::parseError(AtomicHTMLToken*)
+inline void HTMLTreeBuilder::parseError(const AtomicHTMLToken&)
{
}
diff --git a/Source/WebCore/html/parser/HTMLTreeBuilder.h b/Source/WebCore/html/parser/HTMLTreeBuilder.h
index 37353f2d7..aeccab45d 100644
--- a/Source/WebCore/html/parser/HTMLTreeBuilder.h
+++ b/Source/WebCore/html/parser/HTMLTreeBuilder.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 Google, Inc. All Rights Reserved.
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -24,68 +24,56 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef HTMLTreeBuilder_h
-#define HTMLTreeBuilder_h
+#pragma once
-#include "FragmentScriptingPermission.h"
#include "HTMLConstructionSite.h"
-#include "HTMLElementStack.h"
-#include "HTMLFormattingElementList.h"
#include "HTMLParserOptions.h"
-#include "HTMLTokenizer.h"
-#include <wtf/Noncopyable.h>
-#include <wtf/OwnPtr.h>
-#include <wtf/PassOwnPtr.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefPtr.h>
-#include <wtf/Vector.h>
#include <wtf/text/StringBuilder.h>
#include <wtf/text/TextPosition.h>
namespace WebCore {
-class AtomicHTMLToken;
-class Document;
-class DocumentFragment;
-class Element;
-class Frame;
-class HTMLToken;
-class HTMLDocument;
-class Node;
+class JSCustomElementInterface;
class HTMLDocumentParser;
+class ScriptElement;
+
+struct CustomElementConstructionData {
+ CustomElementConstructionData(Ref<JSCustomElementInterface>&&, const AtomicString& name, Vector<Attribute>&&);
+ ~CustomElementConstructionData();
+
+ Ref<JSCustomElementInterface> elementInterface;
+ AtomicString name;
+ Vector<Attribute> attributes;
+};
class HTMLTreeBuilder {
- WTF_MAKE_NONCOPYABLE(HTMLTreeBuilder); WTF_MAKE_FAST_ALLOCATED;
+ WTF_MAKE_FAST_ALLOCATED;
public:
HTMLTreeBuilder(HTMLDocumentParser&, HTMLDocument&, ParserContentPolicy, const HTMLParserOptions&);
- HTMLTreeBuilder(HTMLDocumentParser&, DocumentFragment&, Element* contextElement, ParserContentPolicy, const HTMLParserOptions&);
- ~HTMLTreeBuilder();
+ HTMLTreeBuilder(HTMLDocumentParser&, DocumentFragment&, Element& contextElement, ParserContentPolicy, const HTMLParserOptions&);
+ void setShouldSkipLeadingNewline(bool);
- const HTMLElementStack* openElements() const { return m_tree.openElements(); }
+ ~HTMLTreeBuilder();
- bool isParsingFragment() const { return !!m_fragmentContext.fragment(); }
-#if ENABLE(TEMPLATE_ELEMENT)
- bool isParsingTemplateContents() const { return m_tree.openElements()->hasTemplateInHTMLScope(); }
-#else
- bool isParsingTemplateContents() const { return false; }
-#endif
- bool isParsingFragmentOrTemplateContents() const { return isParsingFragment() || isParsingTemplateContents(); }
+ bool isParsingFragment() const;
- void detach();
+ void constructTree(AtomicHTMLToken&&);
- void constructTree(AtomicHTMLToken*);
+ bool isParsingTemplateContents() const;
+ bool hasParserBlockingScriptWork() const;
- bool hasParserBlockingScript() const { return !!m_scriptToProcess; }
// Must be called to take the parser-blocking script before calling the parser again.
- PassRefPtr<Element> takeScriptToProcess(TextPosition& scriptStartPosition);
+ RefPtr<ScriptElement> takeScriptToProcess(TextPosition& scriptStartPosition);
+
+ std::unique_ptr<CustomElementConstructionData> takeCustomElementConstructionData() { return WTFMove(m_customElementToConstruct); }
+ void didCreateCustomOrCallbackElement(Ref<Element>&&, CustomElementConstructionData&);
// Done, close any open tags, etc.
void finished();
- void setShouldSkipLeadingNewline(bool shouldSkip) { m_shouldSkipLeadingNewline = shouldSkip; }
-
private:
class ExternalCharacterTokenBuffer;
+
// Represents HTML5 "insertion mode"
// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#insertion-mode
enum class InsertionMode {
@@ -114,52 +102,52 @@ private:
AfterAfterFrameset,
};
-#if PLATFORM(IOS)
+ bool isParsingFragmentOrTemplateContents() const;
+
+#if ENABLE(TELEPHONE_NUMBER_DETECTION) && PLATFORM(IOS)
void insertPhoneNumberLink(const String&);
void linkifyPhoneNumbers(const String&);
#endif
- void processToken(AtomicHTMLToken*);
-
- void processDoctypeToken(AtomicHTMLToken*);
- void processStartTag(AtomicHTMLToken*);
- void processEndTag(AtomicHTMLToken*);
- void processComment(AtomicHTMLToken*);
- void processCharacter(AtomicHTMLToken*);
- void processEndOfFile(AtomicHTMLToken*);
-
- bool processStartTagForInHead(AtomicHTMLToken*);
- void processStartTagForInBody(AtomicHTMLToken*);
- void processStartTagForInTable(AtomicHTMLToken*);
- void processEndTagForInBody(AtomicHTMLToken*);
- void processEndTagForInTable(AtomicHTMLToken*);
- void processEndTagForInTableBody(AtomicHTMLToken*);
- void processEndTagForInRow(AtomicHTMLToken*);
- void processEndTagForInCell(AtomicHTMLToken*);
-
- void processIsindexStartTagForInBody(AtomicHTMLToken*);
- void processHtmlStartTagForInBody(AtomicHTMLToken*);
- bool processBodyEndTagForInBody(AtomicHTMLToken*);
+ void processToken(AtomicHTMLToken&&);
+
+ void processDoctypeToken(AtomicHTMLToken&&);
+ void processStartTag(AtomicHTMLToken&&);
+ void processEndTag(AtomicHTMLToken&&);
+ void processComment(AtomicHTMLToken&&);
+ void processCharacter(AtomicHTMLToken&&);
+ void processEndOfFile(AtomicHTMLToken&&);
+
+ bool processStartTagForInHead(AtomicHTMLToken&&);
+ void processStartTagForInBody(AtomicHTMLToken&&);
+ void processStartTagForInTable(AtomicHTMLToken&&);
+ void processEndTagForInBody(AtomicHTMLToken&&);
+ void processEndTagForInTable(AtomicHTMLToken&&);
+ void processEndTagForInTableBody(AtomicHTMLToken&&);
+ void processEndTagForInRow(AtomicHTMLToken&&);
+ void processEndTagForInCell(AtomicHTMLToken&&);
+
+ void processHtmlStartTagForInBody(AtomicHTMLToken&&);
+ bool processBodyEndTagForInBody(AtomicHTMLToken&&);
bool processTableEndTagForInTable();
bool processCaptionEndTagForInCaption();
bool processColgroupEndTagForInColumnGroup();
bool processTrEndTagForInRow();
- // FIXME: This function should be inlined into its one call site or it
- // needs to assert which tokens it can be called with.
- void processAnyOtherEndTagForInBody(AtomicHTMLToken*);
+
+ void processAnyOtherEndTagForInBody(AtomicHTMLToken&&);
void processCharacterBuffer(ExternalCharacterTokenBuffer&);
inline void processCharacterBufferForInBody(ExternalCharacterTokenBuffer&);
- void processFakeStartTag(const QualifiedName&, const Vector<Attribute>& attributes = Vector<Attribute>());
+ void processFakeStartTag(const QualifiedName&, Vector<Attribute>&& attributes = Vector<Attribute>());
void processFakeEndTag(const QualifiedName&);
void processFakeEndTag(const AtomicString&);
void processFakeCharacters(const String&);
void processFakePEndTagIfPInButtonScope();
- void processGenericRCDATAStartTag(AtomicHTMLToken*);
- void processGenericRawTextStartTag(AtomicHTMLToken*);
- void processScriptStartTag(AtomicHTMLToken*);
+ void processGenericRCDATAStartTag(AtomicHTMLToken&&);
+ void processGenericRawTextStartTag(AtomicHTMLToken&&);
+ void processScriptStartTag(AtomicHTMLToken&&);
// Default processing for the different insertion modes.
void defaultForInitial();
@@ -170,78 +158,101 @@ private:
void defaultForAfterHead();
void defaultForInTableText();
- inline bool shouldProcessTokenInForeignContent(AtomicHTMLToken*);
- void processTokenInForeignContent(AtomicHTMLToken*);
-
- Vector<Attribute> attributesForIsindexInput(AtomicHTMLToken*);
+ bool shouldProcessTokenInForeignContent(const AtomicHTMLToken&);
+ void processTokenInForeignContent(AtomicHTMLToken&&);
+
+ HTMLStackItem& adjustedCurrentStackItem() const;
- void callTheAdoptionAgency(AtomicHTMLToken*);
+ void callTheAdoptionAgency(AtomicHTMLToken&);
void closeTheCell();
- template <bool shouldClose(const HTMLStackItem*)>
- void processCloseWhenNestedTag(AtomicHTMLToken*);
-
- void parseError(AtomicHTMLToken*);
+ template <bool shouldClose(const HTMLStackItem&)> void processCloseWhenNestedTag(AtomicHTMLToken&&);
- InsertionMode insertionMode() const { return m_insertionMode; }
- void setInsertionMode(InsertionMode mode) { m_insertionMode = mode; }
+ void parseError(const AtomicHTMLToken&);
void resetInsertionModeAppropriately();
-#if ENABLE(TEMPLATE_ELEMENT)
- void processTemplateStartTag(AtomicHTMLToken*);
- bool processTemplateEndTag(AtomicHTMLToken*);
- bool processEndOfFileForInTemplateContents(AtomicHTMLToken*);
-#endif
+ void insertGenericHTMLElement(AtomicHTMLToken&&);
+
+ void processTemplateStartTag(AtomicHTMLToken&&);
+ bool processTemplateEndTag(AtomicHTMLToken&&);
+ bool processEndOfFileForInTemplateContents(AtomicHTMLToken&&);
class FragmentParsingContext {
- WTF_MAKE_NONCOPYABLE(FragmentParsingContext);
public:
FragmentParsingContext();
- FragmentParsingContext(DocumentFragment&, Element* contextElement);
- ~FragmentParsingContext();
+ FragmentParsingContext(DocumentFragment&, Element& contextElement);
- DocumentFragment* fragment() const { return m_fragment; }
- Element* contextElement() const { ASSERT(m_fragment); return m_contextElement; }
+ DocumentFragment* fragment() const;
+ Element& contextElement() const;
+ HTMLStackItem& contextElementStackItem() const;
private:
- DocumentFragment* m_fragment;
- Element* m_contextElement;
+ DocumentFragment* m_fragment { nullptr };
+ RefPtr<HTMLStackItem> m_contextElementStackItem;
};
- bool m_framesetOk;
-#ifndef NDEBUG
- bool m_isAttached;
-#endif
- FragmentParsingContext m_fragmentContext;
- HTMLConstructionSite m_tree;
-
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#insertion-mode
- InsertionMode m_insertionMode;
+ HTMLDocumentParser& m_parser;
+ const HTMLParserOptions m_options;
+ const FragmentParsingContext m_fragmentContext;
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#original-insertion-mode
- InsertionMode m_originalInsertionMode;
+ HTMLConstructionSite m_tree;
-#if ENABLE(TEMPLATE_ELEMENT)
- Vector<InsertionMode> m_templateInsertionModes;
-#endif
+ // https://html.spec.whatwg.org/multipage/syntax.html#the-insertion-mode
+ InsertionMode m_insertionMode { InsertionMode::Initial };
+ InsertionMode m_originalInsertionMode { InsertionMode::Initial };
+ Vector<InsertionMode, 1> m_templateInsertionModes;
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#pending-table-character-tokens
+ // https://html.spec.whatwg.org/multipage/syntax.html#concept-pending-table-char-tokens
StringBuilder m_pendingTableCharacters;
- bool m_shouldSkipLeadingNewline;
+ RefPtr<ScriptElement> m_scriptToProcess; // <script> tag which needs processing before resuming the parser.
+ TextPosition m_scriptToProcessStartPosition; // Starting line number of the script tag needing processing.
- // We access parser because HTML5 spec requires that we be able to change the state of the tokenizer
- // from within parser actions. We also need it to track the current position.
- HTMLDocumentParser& m_parser;
+ std::unique_ptr<CustomElementConstructionData> m_customElementToConstruct;
- RefPtr<Element> m_scriptToProcess; // <script> tag which needs processing before resuming the parser.
- TextPosition m_scriptToProcessStartPosition; // Starting line number of the script tag needing processing.
+ bool m_shouldSkipLeadingNewline { false };
+
+ bool m_framesetOk { true };
- HTMLParserOptions m_options;
+#if !ASSERT_DISABLED
+ bool m_destroyed { false };
+ bool m_destructionProhibited { true };
+#endif
};
+inline HTMLTreeBuilder::~HTMLTreeBuilder()
+{
+#if !ASSERT_DISABLED
+ ASSERT(!m_destroyed);
+ ASSERT(!m_destructionProhibited);
+ m_destroyed = true;
+#endif
+}
+
+inline void HTMLTreeBuilder::setShouldSkipLeadingNewline(bool shouldSkip)
+{
+ ASSERT(!m_destroyed);
+ m_shouldSkipLeadingNewline = shouldSkip;
}
-#endif
+inline bool HTMLTreeBuilder::isParsingFragment() const
+{
+ ASSERT(!m_destroyed);
+ return !!m_fragmentContext.fragment();
+}
+
+inline bool HTMLTreeBuilder::hasParserBlockingScriptWork() const
+{
+ ASSERT(!m_destroyed);
+ ASSERT(!(m_scriptToProcess && m_customElementToConstruct));
+ return m_scriptToProcess || m_customElementToConstruct;
+}
+
+inline DocumentFragment* HTMLTreeBuilder::FragmentParsingContext::fragment() const
+{
+ return m_fragment;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/HTMLViewSourceParser.cpp b/Source/WebCore/html/parser/HTMLViewSourceParser.cpp
deleted file mode 100644
index 35ccebea2..000000000
--- a/Source/WebCore/html/parser/HTMLViewSourceParser.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2010 Google, Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "HTMLViewSourceParser.h"
-
-#include "HTMLDocumentParser.h"
-#include "HTMLNames.h"
-
-namespace WebCore {
-
-HTMLViewSourceParser::HTMLViewSourceParser(HTMLViewSourceDocument& document)
- : DecodedDataDocumentParser(document)
- , m_tokenizer(std::make_unique<HTMLTokenizer>(HTMLParserOptions(document)))
-{
-}
-
-HTMLViewSourceParser::~HTMLViewSourceParser()
-{
-}
-
-void HTMLViewSourceParser::insert(const SegmentedString&)
-{
- ASSERT_NOT_REACHED();
-}
-
-void HTMLViewSourceParser::pumpTokenizer()
-{
- while (true) {
- m_sourceTracker.start(m_input.current(), m_tokenizer.get(), m_token);
- if (!m_tokenizer->nextToken(m_input.current(), m_token))
- break;
- m_sourceTracker.end(m_input.current(), m_tokenizer.get(), m_token);
-
- document()->addSource(sourceForToken(), m_token);
- updateTokenizerState();
- m_token.clear();
- }
-}
-
-void HTMLViewSourceParser::append(PassRefPtr<StringImpl> input)
-{
- m_input.appendToEnd(String(input));
- pumpTokenizer();
-}
-
-String HTMLViewSourceParser::sourceForToken()
-{
- return m_sourceTracker.sourceForToken(m_token);
-}
-
-void HTMLViewSourceParser::updateTokenizerState()
-{
- // FIXME: The tokenizer should do this work for us.
- if (m_token.type() != HTMLToken::StartTag)
- return;
- m_tokenizer->updateStateFor(AtomicString(m_token.name()));
-}
-
-void HTMLViewSourceParser::finish()
-{
- if (!m_input.haveSeenEndOfFile())
- m_input.markEndOfFile();
- pumpTokenizer();
- document()->finishedParsing();
-}
-
-}
diff --git a/Source/WebCore/html/parser/HTMLViewSourceParser.h b/Source/WebCore/html/parser/HTMLViewSourceParser.h
deleted file mode 100644
index c48adbeb7..000000000
--- a/Source/WebCore/html/parser/HTMLViewSourceParser.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2010 Google, Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef HTMLViewSourceParser_h
-#define HTMLViewSourceParser_h
-
-#include "DecodedDataDocumentParser.h"
-#include "HTMLInputStream.h"
-#include "HTMLSourceTracker.h"
-#include "HTMLToken.h"
-#include "HTMLTokenizer.h"
-#include "HTMLViewSourceDocument.h"
-#include <wtf/PassOwnPtr.h>
-
-namespace WebCore {
-
-class HTMLTokenizer;
-class HTMLScriptRunner;
-class HTMLTreeBuilder;
-class HTMLPreloadScanner;
-class ScriptController;
-class ScriptSourceCode;
-
-class HTMLViewSourceParser : public DecodedDataDocumentParser {
-public:
- static PassRefPtr<HTMLViewSourceParser> create(HTMLViewSourceDocument& document)
- {
- return adoptRef(new HTMLViewSourceParser(document));
- }
- virtual ~HTMLViewSourceParser();
-
-protected:
- explicit HTMLViewSourceParser(HTMLViewSourceDocument&);
-
- HTMLTokenizer* tokenizer() const { return m_tokenizer.get(); }
-
-private:
- // DocumentParser
- virtual void insert(const SegmentedString&) override;
- virtual void append(PassRefPtr<StringImpl>) override;
- virtual void finish() override;
-
- HTMLViewSourceDocument* document() const { return static_cast<HTMLViewSourceDocument*>(DecodedDataDocumentParser::document()); }
-
- void pumpTokenizer();
- String sourceForToken();
- void updateTokenizerState();
-
- HTMLInputStream m_input;
- HTMLToken m_token;
- HTMLSourceTracker m_sourceTracker;
- std::unique_ptr<HTMLTokenizer> m_tokenizer;
-};
-
-}
-
-#endif
diff --git a/Source/WebCore/html/parser/InputStreamPreprocessor.h b/Source/WebCore/html/parser/InputStreamPreprocessor.h
index ffd639abe..361f65301 100644
--- a/Source/WebCore/html/parser/InputStreamPreprocessor.h
+++ b/Source/WebCore/html/parser/InputStreamPreprocessor.h
@@ -25,25 +25,20 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef InputStreamPreprocessor_h
-#define InputStreamPreprocessor_h
+#pragma once
#include "SegmentedString.h"
-#include <wtf/Noncopyable.h>
+#include <wtf/unicode/CharacterNames.h>
namespace WebCore {
-const LChar kEndOfFileMarker = 0;
-
// http://www.whatwg.org/specs/web-apps/current-work/#preprocessing-the-input-stream
template <typename Tokenizer>
class InputStreamPreprocessor {
- WTF_MAKE_NONCOPYABLE(InputStreamPreprocessor);
public:
- InputStreamPreprocessor(Tokenizer* tokenizer)
+ explicit InputStreamPreprocessor(Tokenizer& tokenizer)
: m_tokenizer(tokenizer)
{
- reset();
}
ALWAYS_INLINE UChar nextInputCharacter() const { return m_nextInputCharacter; }
@@ -51,88 +46,79 @@ public:
// Returns whether we succeeded in peeking at the next character.
// The only way we can fail to peek is if there are no more
// characters in |source| (after collapsing \r\n, etc).
- ALWAYS_INLINE bool peek(SegmentedString& source)
+ ALWAYS_INLINE bool peek(SegmentedString& source, bool skipNullCharacters = false)
{
- m_nextInputCharacter = source.currentChar();
+ if (UNLIKELY(source.isEmpty()))
+ return false;
+
+ m_nextInputCharacter = source.currentCharacter();
// Every branch in this function is expensive, so we have a
// fast-reject branch for characters that don't require special
// handling. Please run the parser benchmark whenever you touch
// this function. It's very hot.
- static const UChar specialCharacterMask = '\n' | '\r' | '\0';
- if (m_nextInputCharacter & ~specialCharacterMask) {
+ constexpr UChar specialCharacterMask = '\n' | '\r' | '\0';
+ if (LIKELY(m_nextInputCharacter & ~specialCharacterMask)) {
m_skipNextNewLine = false;
return true;
}
- return processNextInputCharacter(source);
+
+ return processNextInputCharacter(source, skipNullCharacters);
}
// Returns whether there are more characters in |source| after advancing.
- ALWAYS_INLINE bool advance(SegmentedString& source)
+ ALWAYS_INLINE bool advance(SegmentedString& source, bool skipNullCharacters = false)
{
- source.advanceAndUpdateLineNumber();
- if (source.isEmpty())
- return false;
- return peek(source);
+ source.advance();
+ return peek(source, skipNullCharacters);
}
-
- bool skipNextNewLine() const { return m_skipNextNewLine; }
-
- void reset(bool skipNextNewLine = false)
+ ALWAYS_INLINE bool advancePastNonNewline(SegmentedString& source, bool skipNullCharacters = false)
{
- m_nextInputCharacter = '\0';
- m_skipNextNewLine = skipNextNewLine;
+ source.advancePastNonNewline();
+ return peek(source, skipNullCharacters);
}
private:
- bool processNextInputCharacter(SegmentedString& source)
+ bool processNextInputCharacter(SegmentedString& source, bool skipNullCharacters)
{
ProcessAgain:
- ASSERT(m_nextInputCharacter == source.currentChar());
-
+ ASSERT(m_nextInputCharacter == source.currentCharacter());
if (m_nextInputCharacter == '\n' && m_skipNextNewLine) {
m_skipNextNewLine = false;
- source.advancePastNewlineAndUpdateLineNumber();
+ source.advancePastNewline();
if (source.isEmpty())
return false;
- m_nextInputCharacter = source.currentChar();
+ m_nextInputCharacter = source.currentCharacter();
}
if (m_nextInputCharacter == '\r') {
m_nextInputCharacter = '\n';
m_skipNextNewLine = true;
- } else {
- m_skipNextNewLine = false;
- // FIXME: The spec indicates that the surrogate pair range as well as
- // a number of specific character values are parse errors and should be replaced
- // by the replacement character. We suspect this is a problem with the spec as doing
- // that filtering breaks surrogate pair handling and causes us not to match Minefield.
- if (m_nextInputCharacter == '\0' && !shouldTreatNullAsEndOfFileMarker(source)) {
- if (m_tokenizer->shouldSkipNullCharacters()) {
- source.advancePastNonNewline();
- if (source.isEmpty())
- return false;
- m_nextInputCharacter = source.currentChar();
- goto ProcessAgain;
- }
- m_nextInputCharacter = 0xFFFD;
- }
+ return true;
+ }
+ m_skipNextNewLine = false;
+ if (m_nextInputCharacter || isAtEndOfFile(source))
+ return true;
+ if (skipNullCharacters && !m_tokenizer.neverSkipNullCharacters()) {
+ source.advancePastNonNewline();
+ if (source.isEmpty())
+ return false;
+ m_nextInputCharacter = source.currentCharacter();
+ goto ProcessAgain;
}
+ m_nextInputCharacter = replacementCharacter;
return true;
}
- bool shouldTreatNullAsEndOfFileMarker(SegmentedString& source) const
+ static bool isAtEndOfFile(SegmentedString& source)
{
return source.isClosed() && source.length() == 1;
}
- Tokenizer* m_tokenizer;
+ Tokenizer& m_tokenizer;
// http://www.whatwg.org/specs/web-apps/current-work/#next-input-character
- UChar m_nextInputCharacter;
- bool m_skipNextNewLine;
+ UChar m_nextInputCharacter { 0 };
+ bool m_skipNextNewLine { false };
};
-}
-
-#endif // InputStreamPreprocessor_h
-
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/NestingLevelIncrementer.h b/Source/WebCore/html/parser/NestingLevelIncrementer.h
index bf08425be..89aea3cc3 100644
--- a/Source/WebCore/html/parser/NestingLevelIncrementer.h
+++ b/Source/WebCore/html/parser/NestingLevelIncrementer.h
@@ -23,8 +23,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef NestingLevelIncrementer_h
-#define NestingLevelIncrementer_h
+#pragma once
#include <wtf/Noncopyable.h>
@@ -48,6 +47,4 @@ private:
unsigned* m_nestingLevel;
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/ParsingUtilities.h b/Source/WebCore/html/parser/ParsingUtilities.h
new file mode 100644
index 000000000..a70d31266
--- /dev/null
+++ b/Source/WebCore/html/parser/ParsingUtilities.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+namespace WebCore {
+
+template<typename CharType>
+bool skipExactly(const CharType*& position, const CharType* end, CharType delimiter)
+{
+ if (position < end && *position == delimiter) {
+ ++position;
+ return true;
+ }
+ return false;
+}
+
+template<typename CharType, bool characterPredicate(CharType)>
+bool skipExactly(const CharType*& position, const CharType* end)
+{
+ if (position < end && characterPredicate(*position)) {
+ ++position;
+ return true;
+ }
+ return false;
+}
+
+template<typename CharType>
+void skipUntil(const CharType*& position, const CharType* end, CharType delimiter)
+{
+ while (position < end && *position != delimiter)
+ ++position;
+}
+
+template<typename CharType, bool characterPredicate(CharType)>
+void skipUntil(const CharType*& position, const CharType* end)
+{
+ while (position < end && !characterPredicate(*position))
+ ++position;
+}
+
+template<typename CharType, bool characterPredicate(CharType)>
+void skipWhile(const CharType*& position, const CharType* end)
+{
+ while (position < end && characterPredicate(*position))
+ ++position;
+}
+
+template<typename CharType, bool characterPredicate(CharType)>
+void reverseSkipWhile(const CharType*& position, const CharType* start)
+{
+ while (position >= start && characterPredicate(*position))
+ --position;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/TextDocumentParser.cpp b/Source/WebCore/html/parser/TextDocumentParser.cpp
index 30bed65b2..f98825b20 100644
--- a/Source/WebCore/html/parser/TextDocumentParser.cpp
+++ b/Source/WebCore/html/parser/TextDocumentParser.cpp
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
@@ -25,8 +25,8 @@
#include "config.h"
#include "TextDocumentParser.h"
-#include "HTMLDocument.h"
#include "HTMLTreeBuilder.h"
+#include "ScriptElement.h"
namespace WebCore {
@@ -34,19 +34,14 @@ using namespace HTMLNames;
TextDocumentParser::TextDocumentParser(HTMLDocument& document)
: HTMLDocumentParser(document)
- , m_haveInsertedFakePreElement(false)
{
}
-TextDocumentParser::~TextDocumentParser()
-{
-}
-
-void TextDocumentParser::append(PassRefPtr<StringImpl> text)
+void TextDocumentParser::append(RefPtr<StringImpl>&& text)
{
if (!m_haveInsertedFakePreElement)
insertFakePreElement();
- HTMLDocumentParser::append(text);
+ HTMLDocumentParser::append(WTFMove(text));
}
void TextDocumentParser::insertFakePreElement()
@@ -58,16 +53,16 @@ void TextDocumentParser::insertFakePreElement()
// distrubing the line/column number calculations.
Vector<Attribute> attributes;
attributes.append(Attribute(styleAttr, "word-wrap: break-word; white-space: pre-wrap;"));
- AtomicHTMLToken fakePre(HTMLToken::StartTag, preTag.localName(), attributes);
- treeBuilder()->constructTree(&fakePre);
+ AtomicHTMLToken fakePre(HTMLToken::StartTag, preTag.localName(), WTFMove(attributes));
+ treeBuilder().constructTree(WTFMove(fakePre));
// Normally we would skip the first \n after a <pre> element, but we don't
// want to skip the first \n for text documents!
- treeBuilder()->setShouldSkipLeadingNewline(false);
+ treeBuilder().setShouldSkipLeadingNewline(false);
// Although Text Documents expose a "pre" element in their DOM, they
// act like a <plaintext> tag, so we have to force plaintext mode.
- forcePlaintextForTextDocument();
+ tokenizer().setPLAINTEXTState();
m_haveInsertedFakePreElement = true;
}
diff --git a/Source/WebCore/html/parser/TextDocumentParser.h b/Source/WebCore/html/parser/TextDocumentParser.h
index dcf235112..2e10a7470 100644
--- a/Source/WebCore/html/parser/TextDocumentParser.h
+++ b/Source/WebCore/html/parser/TextDocumentParser.h
@@ -10,10 +10,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
@@ -22,9 +22,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
-#ifndef TextDocumentParser_h
-#define TextDocumentParser_h
+#pragma once
#include "HTMLDocumentParser.h"
@@ -32,21 +30,19 @@ namespace WebCore {
class TextDocumentParser final : public HTMLDocumentParser {
public:
- static PassRefPtr<TextDocumentParser> create(HTMLDocument& document)
+ static Ref<TextDocumentParser> create(HTMLDocument& document)
{
- return adoptRef(new TextDocumentParser(document));
+ return adoptRef(*new TextDocumentParser(document));
}
- virtual ~TextDocumentParser();
private:
explicit TextDocumentParser(HTMLDocument&);
- virtual void append(PassRefPtr<StringImpl>) override;
+ void append(RefPtr<StringImpl>&&) override;
+
void insertFakePreElement();
- bool m_haveInsertedFakePreElement;
+ bool m_haveInsertedFakePreElement { false };
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/TextViewSourceParser.cpp b/Source/WebCore/html/parser/TextViewSourceParser.cpp
deleted file mode 100644
index 1f25721eb..000000000
--- a/Source/WebCore/html/parser/TextViewSourceParser.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2010 Google, Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "TextViewSourceParser.h"
-
-#include "HTMLTokenizer.h"
-
-namespace WebCore {
-
-TextViewSourceParser::TextViewSourceParser(HTMLViewSourceDocument& document)
- : HTMLViewSourceParser(document)
-{
- tokenizer()->setState(HTMLTokenizer::PLAINTEXTState);
-}
-
-TextViewSourceParser::~TextViewSourceParser()
-{
-}
-
-}
diff --git a/Source/WebCore/html/parser/TextViewSourceParser.h b/Source/WebCore/html/parser/TextViewSourceParser.h
deleted file mode 100644
index c80932ca6..000000000
--- a/Source/WebCore/html/parser/TextViewSourceParser.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2010 Google, Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef TextViewSourceParser_h
-#define TextViewSourceParser_h
-
-#include "HTMLViewSourceParser.h"
-
-namespace WebCore {
-
-class TextViewSourceParser final : public HTMLViewSourceParser {
-public:
- static PassRefPtr<TextViewSourceParser> create(HTMLViewSourceDocument& document)
- {
- return adoptRef(new TextViewSourceParser(document));
- }
- virtual ~TextViewSourceParser();
-
-private:
- explicit TextViewSourceParser(HTMLViewSourceDocument&);
-};
-
-}
-
-#endif
diff --git a/Source/WebCore/html/parser/XSSAuditor.cpp b/Source/WebCore/html/parser/XSSAuditor.cpp
index 1bf5a096e..f314dd438 100644
--- a/Source/WebCore/html/parser/XSSAuditor.cpp
+++ b/Source/WebCore/html/parser/XSSAuditor.cpp
@@ -27,7 +27,6 @@
#include "config.h"
#include "XSSAuditor.h"
-#include "ContentSecurityPolicy.h"
#include "DecodeEscapeSequences.h"
#include "Document.h"
#include "DocumentLoader.h"
@@ -37,14 +36,13 @@
#include "HTMLNames.h"
#include "HTMLParamElement.h"
#include "HTMLParserIdioms.h"
+#include "SVGNames.h"
#include "Settings.h"
#include "TextResourceDecoder.h"
#include "XLinkNames.h"
+#include <wtf/ASCIICType.h>
#include <wtf/MainThread.h>
-
-#if ENABLE(SVG)
-#include "SVGNames.h"
-#endif
+#include <wtf/NeverDestroyed.h>
namespace WebCore {
@@ -57,14 +55,11 @@ static bool isNonCanonicalCharacter(UChar c)
// Note, we don't remove backslashes like PHP stripslashes(), which among other things converts "\\0" to the \0 character.
// Instead, we remove backslashes and zeros (since the string "\\0" =(remove backslashes)=> "0"). However, this has the
// adverse effect that we remove any legitimate zeros from a string.
+ // We also remove forward-slash, because it is common for some servers to collapse successive path components, eg,
+ // a//b becomes a/b.
//
- // For instance: new String("http://localhost:8000") => new String("http://localhost:8").
- return (c == '\\' || c == '0' || c == '\0' || c >= 127);
-}
-
-static String canonicalize(const String& string)
-{
- return string.removeCharacters(&isNonCanonicalCharacter);
+ // For instance: new String("http://localhost:8000") => new String("http:localhost:8").
+ return (c == '\\' || c == '0' || c == '\0' || c == '/' || c >= 127);
}
static bool isRequiredForInjection(UChar c)
@@ -90,17 +85,28 @@ static bool isJSNewline(UChar c)
static bool startsHTMLCommentAt(const String& string, size_t start)
{
- return (start + 3 < string.length() && string[start] == '<' && string[start+1] == '!' && string[start+2] == '-' && string[start+3] == '-');
+ return (start + 3 < string.length() && string[start] == '<' && string[start + 1] == '!' && string[start + 2] == '-' && string[start + 3] == '-');
}
static bool startsSingleLineCommentAt(const String& string, size_t start)
{
- return (start + 1 < string.length() && string[start] == '/' && string[start+1] == '/');
+ return (start + 1 < string.length() && string[start] == '/' && string[start + 1] == '/');
}
static bool startsMultiLineCommentAt(const String& string, size_t start)
{
- return (start + 1 < string.length() && string[start] == '/' && string[start+1] == '*');
+ return (start + 1 < string.length() && string[start] == '/' && string[start + 1] == '*');
+}
+
+static bool startsOpeningScriptTagAt(const String& string, size_t start)
+{
+ return start + 6 < string.length() && string[start] == '<'
+ && WTF::toASCIILowerUnchecked(string[start + 1]) == 's'
+ && WTF::toASCIILowerUnchecked(string[start + 2]) == 'c'
+ && WTF::toASCIILowerUnchecked(string[start + 3]) == 'r'
+ && WTF::toASCIILowerUnchecked(string[start + 4]) == 'i'
+ && WTF::toASCIILowerUnchecked(string[start + 5]) == 'p'
+ && WTF::toASCIILowerUnchecked(string[start + 6]) == 't';
}
// If other files need this, we should move this to HTMLParserIdioms.h
@@ -140,7 +146,7 @@ static bool isNameOfInlineEventHandler(const Vector<UChar, 32>& name)
static bool isDangerousHTTPEquiv(const String& value)
{
String equiv = value.stripWhiteSpace();
- return equalIgnoringCase(equiv, "refresh") || equalIgnoringCase(equiv, "set-cookie");
+ return equalLettersIgnoringASCIICase(equiv, "refresh") || equalLettersIgnoringASCIICase(equiv, "set-cookie");
}
static inline String decode16BitUnicodeEscapeSequences(const String& string)
@@ -165,36 +171,79 @@ static String fullyDecodeString(const String& string, const TextEncoding& encodi
workingString = decode16BitUnicodeEscapeSequences(decodeStandardURLEscapeSequences(workingString, encoding));
} while (workingString.length() < oldWorkingStringLength);
workingString.replace('+', ' ');
- workingString = canonicalize(workingString);
return workingString;
}
-static ContentSecurityPolicy::ReflectedXSSDisposition combineXSSProtectionHeaderAndCSP(ContentSecurityPolicy::ReflectedXSSDisposition xssProtection, ContentSecurityPolicy::ReflectedXSSDisposition reflectedXSS)
-{
- ContentSecurityPolicy::ReflectedXSSDisposition result = std::max(xssProtection, reflectedXSS);
-
- if (result == ContentSecurityPolicy::ReflectedXSSInvalid || result == ContentSecurityPolicy::FilterReflectedXSS || result == ContentSecurityPolicy::ReflectedXSSUnset)
- return ContentSecurityPolicy::FilterReflectedXSS;
+static void truncateForSrcLikeAttribute(String& decodedSnippet)
+{
+ // In HTTP URLs, characters following the first ?, #, or third slash may come from
+ // the page itself and can be merely ignored by an attacker's server when a remote
+ // script or script-like resource is requested. In data URLs, the payload starts at
+ // the first comma, and the first /*, //, or <!-- may introduce a comment. Also
+ // data URLs may use the same string literal tricks as with script content itself.
+ // In either case, content following this may come from the page and may be ignored
+ // when the script is executed. Also, any of these characters may now be represented
+ // by the (enlarged) set of HTML5 entities.
+ // For simplicity, we don't differentiate based on URL scheme, and stop at the first
+ // & (since it might be part of an entity for any of the subsequent punctuation)
+ // the first # or ?, the third slash, or the first slash, <, ', or " once a comma
+ // is seen.
+ int slashCount = 0;
+ bool commaSeen = false;
+ for (size_t currentLength = 0; currentLength < decodedSnippet.length(); ++currentLength) {
+ UChar currentChar = decodedSnippet[currentLength];
+ if (currentChar == '&'
+ || currentChar == '?'
+ || currentChar == '#'
+ || ((currentChar == '/' || currentChar == '\\') && (commaSeen || ++slashCount > 2))
+ || (currentChar == '<' && commaSeen)
+ || (currentChar == '\'' && commaSeen)
+ || (currentChar == '"' && commaSeen)) {
+ decodedSnippet.truncate(currentLength);
+ return;
+ }
+ if (currentChar == ',')
+ commaSeen = true;
+ }
+}
- return result;
+static void truncateForScriptLikeAttribute(String& decodedSnippet)
+{
+ // Beware of trailing characters which came from the page itself, not the
+ // injected vector. Excluding the terminating character covers common cases
+ // where the page immediately ends the attribute, but doesn't cover more
+ // complex cases where there is other page data following the injection.
+ // Generally, these won't parse as JavaScript, so the injected vector
+ // typically excludes them from consideration via a single-line comment or
+ // by enclosing them in a string literal terminated later by the page's own
+ // closing punctuation. Since the snippet has not been parsed, the vector
+ // may also try to introduce these via entities. As a result, we'd like to
+ // stop before the first "//", the first <!--, the first entity, or the first
+ // quote not immediately following the first equals sign (taking whitespace
+ // into consideration). To keep things simpler, we don't try to distinguish
+ // between entity-introducing ampersands vs. other uses, nor do we bother to
+ // check for a second slash for a comment, nor do we bother to check for
+ // !-- following a less-than sign. We stop instead on any ampersand
+ // slash, or less-than sign.
+ size_t position = 0;
+ if ((position = decodedSnippet.find('=')) != notFound
+ && (position = decodedSnippet.find(isNotHTMLSpace, position + 1)) != notFound
+ && (position = decodedSnippet.find(isTerminatingCharacter, isHTMLQuote(decodedSnippet[position]) ? position + 1 : position)) != notFound) {
+ decodedSnippet.truncate(position);
+ }
}
static bool isSemicolonSeparatedAttribute(const HTMLToken::Attribute& attribute)
{
-#if ENABLE(SVG)
return threadSafeMatch(attribute.name, SVGNames::valuesAttr);
-#else
- UNUSED_PARAM(attribute);
- return false;
-#endif
}
static bool semicolonSeparatedValueContainsJavaScriptURL(const String& value)
{
Vector<String> valueList;
value.split(';', valueList);
- for (size_t i = 0; i < valueList.size(); ++i) {
- if (protocolIsJavaScript(valueList[i]))
+ for (auto& value : valueList) {
+ if (protocolIsJavaScript(value))
return true;
}
return false;
@@ -202,8 +251,7 @@ static bool semicolonSeparatedValueContainsJavaScriptURL(const String& value)
XSSAuditor::XSSAuditor()
: m_isEnabled(false)
- , m_xssProtection(ContentSecurityPolicy::FilterReflectedXSS)
- , m_didSendValidCSPHeader(false)
+ , m_xssProtection(XSSProtectionDisposition::Enabled)
, m_didSendValidXSSProtectionHeader(false)
, m_state(Uninitialized)
, m_scriptTagNestingLevel(0)
@@ -240,7 +288,7 @@ void XSSAuditor::init(Document* document, XSSAuditorDelegate* auditorDelegate)
if (!m_isEnabled)
return;
- m_documentURL = document->url().copy();
+ m_documentURL = document->url().isolatedCopy();
// In theory, the Document could have detached from the Frame after the
// XSSAuditor was constructed.
@@ -263,45 +311,42 @@ void XSSAuditor::init(Document* document, XSSAuditorDelegate* auditorDelegate)
if (document->decoder())
m_encoding = document->decoder()->encoding();
- m_decodedURL = fullyDecodeString(m_documentURL.string(), m_encoding);
+ m_decodedURL = canonicalize(m_documentURL.string(), TruncationStyle::None);
if (m_decodedURL.find(isRequiredForInjection) == notFound)
m_decodedURL = String();
String httpBodyAsString;
if (DocumentLoader* documentLoader = document->frame()->loader().documentLoader()) {
- DEFINE_STATIC_LOCAL(String, XSSProtectionHeader, (ASCIILiteral("X-XSS-Protection")));
+ static NeverDestroyed<String> XSSProtectionHeader(ASCIILiteral("X-XSS-Protection"));
String headerValue = documentLoader->response().httpHeaderField(XSSProtectionHeader);
String errorDetails;
unsigned errorPosition = 0;
- String reportURL;
- URL xssProtectionReportURL;
-
- // Process the X-XSS-Protection header, then mix in the CSP header's value.
- ContentSecurityPolicy::ReflectedXSSDisposition xssProtectionHeader = parseXSSProtectionHeader(headerValue, errorDetails, errorPosition, reportURL);
- m_didSendValidXSSProtectionHeader = xssProtectionHeader != ContentSecurityPolicy::ReflectedXSSUnset && xssProtectionHeader != ContentSecurityPolicy::ReflectedXSSInvalid;
- if ((xssProtectionHeader == ContentSecurityPolicy::FilterReflectedXSS || xssProtectionHeader == ContentSecurityPolicy::BlockReflectedXSS) && !reportURL.isEmpty()) {
- xssProtectionReportURL = document->completeURL(reportURL);
- if (MixedContentChecker::isMixedContent(document->securityOrigin(), xssProtectionReportURL)) {
+ String parsedReportURL;
+ URL reportURL;
+ m_xssProtection = parseXSSProtectionHeader(headerValue, errorDetails, errorPosition, parsedReportURL);
+ m_didSendValidXSSProtectionHeader = !headerValue.isNull() && m_xssProtection != XSSProtectionDisposition::Invalid;
+
+ if ((m_xssProtection == XSSProtectionDisposition::Enabled || m_xssProtection == XSSProtectionDisposition::BlockEnabled) && !parsedReportURL.isEmpty()) {
+ reportURL = document->completeURL(parsedReportURL);
+ if (MixedContentChecker::isMixedContent(document->securityOrigin(), reportURL)) {
errorDetails = "insecure reporting URL for secure page";
- xssProtectionHeader = ContentSecurityPolicy::ReflectedXSSInvalid;
- xssProtectionReportURL = URL();
+ m_xssProtection = XSSProtectionDisposition::Invalid;
+ reportURL = URL();
+ m_didSendValidXSSProtectionHeader = false;
}
}
- if (xssProtectionHeader == ContentSecurityPolicy::ReflectedXSSInvalid)
- document->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Error parsing header X-XSS-Protection: " + headerValue + ": " + errorDetails + " at character position " + String::format("%u", errorPosition) + ". The default protections will be applied.");
-
- ContentSecurityPolicy::ReflectedXSSDisposition cspHeader = document->contentSecurityPolicy()->reflectedXSSDisposition();
- m_didSendValidCSPHeader = cspHeader != ContentSecurityPolicy::ReflectedXSSUnset && cspHeader != ContentSecurityPolicy::ReflectedXSSInvalid;
+ if (m_xssProtection == XSSProtectionDisposition::Invalid) {
+ document->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Error parsing header X-XSS-Protection: " + headerValue + ": " + errorDetails + " at character position " + String::format("%u", errorPosition) + ". The default protections will be applied.");
+ m_xssProtection = XSSProtectionDisposition::Enabled;
+ }
- m_xssProtection = combineXSSProtectionHeaderAndCSP(xssProtectionHeader, cspHeader);
- // FIXME: Combine the two report URLs in some reasonable way.
if (auditorDelegate)
- auditorDelegate->setReportURL(xssProtectionReportURL.copy());
+ auditorDelegate->setReportURL(reportURL.isolatedCopy());
FormData* httpBody = documentLoader->originalRequest().httpBody();
if (httpBody && !httpBody->isEmpty()) {
httpBodyAsString = httpBody->flattenToString();
if (!httpBodyAsString.isEmpty()) {
- m_decodedHTTPBody = fullyDecodeString(httpBodyAsString, m_encoding);
+ m_decodedHTTPBody = canonicalize(httpBodyAsString, TruncationStyle::None);
if (m_decodedHTTPBody.find(isRequiredForInjection) == notFound)
m_decodedHTTPBody = String();
if (m_decodedHTTPBody.length() >= minimumLengthForSuffixTree)
@@ -319,7 +364,7 @@ void XSSAuditor::init(Document* document, XSSAuditorDelegate* auditorDelegate)
std::unique_ptr<XSSInfo> XSSAuditor::filterToken(const FilterTokenRequest& request)
{
ASSERT(m_state == Initialized);
- if (!m_isEnabled || m_xssProtection == ContentSecurityPolicy::AllowReflectedXSS)
+ if (!m_isEnabled || m_xssProtection == XSSProtectionDisposition::Disabled)
return nullptr;
bool didBlockScript = false;
@@ -335,8 +380,8 @@ std::unique_ptr<XSSInfo> XSSAuditor::filterToken(const FilterTokenRequest& reque
if (!didBlockScript)
return nullptr;
- bool didBlockEntirePage = (m_xssProtection == ContentSecurityPolicy::BlockReflectedXSS);
- return std::make_unique<XSSInfo>(didBlockEntirePage, m_didSendValidXSSProtectionHeader, m_didSendValidCSPHeader);
+ bool didBlockEntirePage = m_xssProtection == XSSProtectionDisposition::BlockEnabled;
+ return std::make_unique<XSSInfo>(m_documentURL, didBlockEntirePage, m_didSendValidXSSProtectionHeader);
}
bool XSSAuditor::filterStartToken(const FilterTokenRequest& request)
@@ -355,8 +400,8 @@ bool XSSAuditor::filterStartToken(const FilterTokenRequest& request)
didBlockScript |= filterEmbedToken(request);
else if (hasName(request.token, appletTag))
didBlockScript |= filterAppletToken(request);
- else if (hasName(request.token, iframeTag))
- didBlockScript |= filterIframeToken(request);
+ else if (hasName(request.token, iframeTag) || hasName(request.token, frameTag))
+ didBlockScript |= filterFrameToken(request);
else if (hasName(request.token, metaTag))
didBlockScript |= filterMetaToken(request);
else if (hasName(request.token, baseTag))
@@ -383,9 +428,10 @@ void XSSAuditor::filterEndToken(const FilterTokenRequest& request)
bool XSSAuditor::filterCharacterToken(const FilterTokenRequest& request)
{
ASSERT(m_scriptTagNestingLevel);
- if (isContainedInRequest(m_cachedDecodedSnippet) && isContainedInRequest(decodedSnippetForJavaScript(request))) {
- request.token.eraseCharacters();
- request.token.appendToCharacter(' '); // Technically, character tokens can't be empty.
+ if (m_wasScriptTagFoundInRequest && isContainedInRequest(canonicalizedSnippetForJavaScript(request))) {
+ request.token.clear();
+ LChar space = ' ';
+ request.token.appendToCharacter(space); // Technically, character tokens can't be empty.
return true;
}
return false;
@@ -396,12 +442,12 @@ bool XSSAuditor::filterScriptToken(const FilterTokenRequest& request)
ASSERT(request.token.type() == HTMLToken::StartTag);
ASSERT(hasName(request.token, scriptTag));
- m_cachedDecodedSnippet = decodedSnippetForName(request);
+ m_wasScriptTagFoundInRequest = isContainedInRequest(canonicalizedSnippetForTagName(request));
bool didBlockScript = false;
- if (isContainedInRequest(decodedSnippetForName(request))) {
- didBlockScript |= eraseAttributeIfInjected(request, srcAttr, blankURL().string(), SrcLikeAttribute);
- didBlockScript |= eraseAttributeIfInjected(request, XLinkNames::hrefAttr, blankURL().string(), SrcLikeAttribute);
+ if (m_wasScriptTagFoundInRequest) {
+ didBlockScript |= eraseAttributeIfInjected(request, srcAttr, blankURL().string(), TruncationStyle::SrcLikeAttribute);
+ didBlockScript |= eraseAttributeIfInjected(request, XLinkNames::hrefAttr, blankURL().string(), TruncationStyle::SrcLikeAttribute);
}
return didBlockScript;
@@ -413,8 +459,8 @@ bool XSSAuditor::filterObjectToken(const FilterTokenRequest& request)
ASSERT(hasName(request.token, objectTag));
bool didBlockScript = false;
- if (isContainedInRequest(decodedSnippetForName(request))) {
- didBlockScript |= eraseAttributeIfInjected(request, dataAttr, blankURL().string(), SrcLikeAttribute);
+ if (isContainedInRequest(canonicalizedSnippetForTagName(request))) {
+ didBlockScript |= eraseAttributeIfInjected(request, dataAttr, blankURL().string(), TruncationStyle::SrcLikeAttribute);
didBlockScript |= eraseAttributeIfInjected(request, typeAttr);
didBlockScript |= eraseAttributeIfInjected(request, classidAttr);
}
@@ -434,7 +480,7 @@ bool XSSAuditor::filterParamToken(const FilterTokenRequest& request)
if (!HTMLParamElement::isURLParameter(String(nameAttribute.value)))
return false;
- return eraseAttributeIfInjected(request, valueAttr, blankURL().string(), SrcLikeAttribute);
+ return eraseAttributeIfInjected(request, valueAttr, blankURL().string(), TruncationStyle::SrcLikeAttribute);
}
bool XSSAuditor::filterEmbedToken(const FilterTokenRequest& request)
@@ -443,9 +489,9 @@ bool XSSAuditor::filterEmbedToken(const FilterTokenRequest& request)
ASSERT(hasName(request.token, embedTag));
bool didBlockScript = false;
- if (isContainedInRequest(decodedSnippetForName(request))) {
- didBlockScript |= eraseAttributeIfInjected(request, codeAttr, String(), SrcLikeAttribute);
- didBlockScript |= eraseAttributeIfInjected(request, srcAttr, blankURL().string(), SrcLikeAttribute);
+ if (isContainedInRequest(canonicalizedSnippetForTagName(request))) {
+ didBlockScript |= eraseAttributeIfInjected(request, codeAttr, String(), TruncationStyle::SrcLikeAttribute);
+ didBlockScript |= eraseAttributeIfInjected(request, srcAttr, blankURL().string(), TruncationStyle::SrcLikeAttribute);
didBlockScript |= eraseAttributeIfInjected(request, typeAttr);
}
return didBlockScript;
@@ -457,21 +503,21 @@ bool XSSAuditor::filterAppletToken(const FilterTokenRequest& request)
ASSERT(hasName(request.token, appletTag));
bool didBlockScript = false;
- if (isContainedInRequest(decodedSnippetForName(request))) {
- didBlockScript |= eraseAttributeIfInjected(request, codeAttr, String(), SrcLikeAttribute);
+ if (isContainedInRequest(canonicalizedSnippetForTagName(request))) {
+ didBlockScript |= eraseAttributeIfInjected(request, codeAttr, String(), TruncationStyle::SrcLikeAttribute);
didBlockScript |= eraseAttributeIfInjected(request, objectAttr);
}
return didBlockScript;
}
-bool XSSAuditor::filterIframeToken(const FilterTokenRequest& request)
+bool XSSAuditor::filterFrameToken(const FilterTokenRequest& request)
{
ASSERT(request.token.type() == HTMLToken::StartTag);
- ASSERT(hasName(request.token, iframeTag));
+ ASSERT(hasName(request.token, iframeTag) || hasName(request.token, frameTag));
- bool didBlockScript = eraseAttributeIfInjected(request, srcdocAttr, String(), ScriptLikeAttribute);
- if (isContainedInRequest(decodedSnippetForName(request)))
- didBlockScript |= eraseAttributeIfInjected(request, srcAttr, String(), SrcLikeAttribute);
+ bool didBlockScript = eraseAttributeIfInjected(request, srcdocAttr, String(), TruncationStyle::ScriptLikeAttribute);
+ if (isContainedInRequest(canonicalizedSnippetForTagName(request)))
+ didBlockScript |= eraseAttributeIfInjected(request, srcAttr, String(), TruncationStyle::SrcLikeAttribute);
return didBlockScript;
}
@@ -505,7 +551,7 @@ bool XSSAuditor::filterInputToken(const FilterTokenRequest& request)
ASSERT(request.token.type() == HTMLToken::StartTag);
ASSERT(hasName(request.token, inputTag));
- return eraseAttributeIfInjected(request, formactionAttr, blankURL().string(), SrcLikeAttribute);
+ return eraseAttributeIfInjected(request, formactionAttr, blankURL().string(), TruncationStyle::SrcLikeAttribute);
}
bool XSSAuditor::filterButtonToken(const FilterTokenRequest& request)
@@ -513,12 +559,12 @@ bool XSSAuditor::filterButtonToken(const FilterTokenRequest& request)
ASSERT(request.token.type() == HTMLToken::StartTag);
ASSERT(hasName(request.token, buttonTag));
- return eraseAttributeIfInjected(request, formactionAttr, blankURL().string(), SrcLikeAttribute);
+ return eraseAttributeIfInjected(request, formactionAttr, blankURL().string(), TruncationStyle::SrcLikeAttribute);
}
bool XSSAuditor::eraseDangerousAttributesIfInjected(const FilterTokenRequest& request)
{
- DEFINE_STATIC_LOCAL(String, safeJavaScriptURL, (ASCIILiteral("javascript:void(0)")));
+ static NeverDestroyed<String> safeJavaScriptURL(ASCIILiteral("javascript:void(0)"));
bool didBlockScript = false;
for (size_t i = 0; i < request.token.attributes().size(); ++i) {
@@ -529,106 +575,75 @@ bool XSSAuditor::eraseDangerousAttributesIfInjected(const FilterTokenRequest& re
bool valueContainsJavaScriptURL = (!isInlineEventHandler && protocolIsJavaScript(strippedValue)) || (isSemicolonSeparatedAttribute(attribute) && semicolonSeparatedValueContainsJavaScriptURL(strippedValue));
if (!isInlineEventHandler && !valueContainsJavaScriptURL)
continue;
- if (!isContainedInRequest(decodedSnippetForAttribute(request, attribute, ScriptLikeAttribute)))
+ if (!isContainedInRequest(canonicalize(snippetFromAttribute(request, attribute), TruncationStyle::ScriptLikeAttribute)))
continue;
request.token.eraseValueOfAttribute(i);
if (valueContainsJavaScriptURL)
- request.token.appendToAttributeValue(i, safeJavaScriptURL);
+ request.token.appendToAttributeValue(i, safeJavaScriptURL.get());
didBlockScript = true;
}
return didBlockScript;
}
-bool XSSAuditor::eraseAttributeIfInjected(const FilterTokenRequest& request, const QualifiedName& attributeName, const String& replacementValue, AttributeKind treatment)
+bool XSSAuditor::eraseAttributeIfInjected(const FilterTokenRequest& request, const QualifiedName& attributeName, const String& replacementValue, TruncationStyle truncationStyle)
{
size_t indexOfAttribute = 0;
- if (findAttributeWithName(request.token, attributeName, indexOfAttribute)) {
- const HTMLToken::Attribute& attribute = request.token.attributes().at(indexOfAttribute);
- if (isContainedInRequest(decodedSnippetForAttribute(request, attribute, treatment))) {
- if (threadSafeMatch(attributeName, srcAttr) && isLikelySafeResource(String(attribute.value)))
- return false;
- if (threadSafeMatch(attributeName, http_equivAttr) && !isDangerousHTTPEquiv(String(attribute.value)))
- return false;
- request.token.eraseValueOfAttribute(indexOfAttribute);
- if (!replacementValue.isEmpty())
- request.token.appendToAttributeValue(indexOfAttribute, replacementValue);
- return true;
- }
+ if (!findAttributeWithName(request.token, attributeName, indexOfAttribute))
+ return false;
+
+ const HTMLToken::Attribute& attribute = request.token.attributes().at(indexOfAttribute);
+ if (!isContainedInRequest(canonicalize(snippetFromAttribute(request, attribute), truncationStyle)))
+ return false;
+
+ if (threadSafeMatch(attributeName, srcAttr)) {
+ if (isLikelySafeResource(String(attribute.value)))
+ return false;
+ } else if (threadSafeMatch(attributeName, http_equivAttr)) {
+ if (!isDangerousHTTPEquiv(String(attribute.value)))
+ return false;
}
- return false;
+
+ request.token.eraseValueOfAttribute(indexOfAttribute);
+ if (!replacementValue.isEmpty())
+ request.token.appendToAttributeValue(indexOfAttribute, replacementValue);
+ return true;
}
-String XSSAuditor::decodedSnippetForName(const FilterTokenRequest& request)
+String XSSAuditor::canonicalizedSnippetForTagName(const FilterTokenRequest& request)
{
// Grab a fixed number of characters equal to the length of the token's name plus one (to account for the "<").
- return fullyDecodeString(request.sourceTracker.sourceForToken(request.token), m_encoding).substring(0, request.token.name().size() + 1);
+ return canonicalize(request.sourceTracker.source(request.token).substring(0, request.token.name().size() + 1), TruncationStyle::None);
}
-String XSSAuditor::decodedSnippetForAttribute(const FilterTokenRequest& request, const HTMLToken::Attribute& attribute, AttributeKind treatment)
+String XSSAuditor::snippetFromAttribute(const FilterTokenRequest& request, const HTMLToken::Attribute& attribute)
{
- // The range doesn't inlcude the character which terminates the value. So,
+ // The range doesn't include the character which terminates the value. So,
// for an input of |name="value"|, the snippet is |name="value|. For an
// unquoted input of |name=value |, the snippet is |name=value|.
// FIXME: We should grab one character before the name also.
- int start = attribute.nameRange.start - request.token.startIndex();
- int end = attribute.valueRange.end - request.token.startIndex();
- String decodedSnippet = fullyDecodeString(request.sourceTracker.sourceForToken(request.token).substring(start, end - start), m_encoding);
- decodedSnippet.truncate(kMaximumFragmentLengthTarget);
- if (treatment == SrcLikeAttribute) {
- int slashCount = 0;
- bool commaSeen = false;
- // In HTTP URLs, characters following the first ?, #, or third slash may come from
- // the page itself and can be merely ignored by an attacker's server when a remote
- // script or script-like resource is requested. In DATA URLS, the payload starts at
- // the first comma, and the the first /*, //, or <!-- may introduce a comment. Characters
- // following this may come from the page itself and may be ignored when the script is
- // executed. For simplicity, we don't differentiate based on URL scheme, and stop at
- // the first # or ?, the third slash, or the first slash or < once a comma is seen.
- for (size_t currentLength = 0; currentLength < decodedSnippet.length(); ++currentLength) {
- UChar currentChar = decodedSnippet[currentLength];
- if (currentChar == '?'
- || currentChar == '#'
- || ((currentChar == '/' || currentChar == '\\') && (commaSeen || ++slashCount > 2))
- || (currentChar == '<' && commaSeen)) {
- decodedSnippet.truncate(currentLength);
- break;
- }
- if (currentChar == ',')
- commaSeen = true;
- }
- } else if (treatment == ScriptLikeAttribute) {
- // Beware of trailing characters which came from the page itself, not the
- // injected vector. Excluding the terminating character covers common cases
- // where the page immediately ends the attribute, but doesn't cover more
- // complex cases where there is other page data following the injection.
- // Generally, these won't parse as javascript, so the injected vector
- // typically excludes them from consideration via a single-line comment or
- // by enclosing them in a string literal terminated later by the page's own
- // closing punctuation. Since the snippet has not been parsed, the vector
- // may also try to introduce these via entities. As a result, we'd like to
- // stop before the first "//", the first <!--, the first entity, or the first
- // quote not immediately following the first equals sign (taking whitespace
- // into consideration). To keep things simpler, we don't try to distinguish
- // between entity-introducing amperands vs. other uses, nor do we bother to
- // check for a second slash for a comment, nor do we bother to check for
- // !-- following a less-than sign. We stop instead on any ampersand
- // slash, or less-than sign.
- size_t position = 0;
- if ((position = decodedSnippet.find("=")) != notFound
- && (position = decodedSnippet.find(isNotHTMLSpace, position + 1)) != notFound
- && (position = decodedSnippet.find(isTerminatingCharacter, isHTMLQuote(decodedSnippet[position]) ? position + 1 : position)) != notFound) {
- decodedSnippet.truncate(position);
- }
+ return request.sourceTracker.source(request.token, attribute.startOffset, attribute.endOffset);
+}
+
+String XSSAuditor::canonicalize(const String& snippet, TruncationStyle truncationStyle)
+{
+ String decodedSnippet = fullyDecodeString(snippet, m_encoding);
+ if (truncationStyle != TruncationStyle::None) {
+ decodedSnippet.truncate(kMaximumFragmentLengthTarget);
+ if (truncationStyle == TruncationStyle::SrcLikeAttribute)
+ truncateForSrcLikeAttribute(decodedSnippet);
+ else if (truncationStyle == TruncationStyle::ScriptLikeAttribute)
+ truncateForScriptLikeAttribute(decodedSnippet);
}
- return decodedSnippet;
+ return decodedSnippet.removeCharacters(&isNonCanonicalCharacter);
}
-String XSSAuditor::decodedSnippetForJavaScript(const FilterTokenRequest& request)
+String XSSAuditor::canonicalizedSnippetForJavaScript(const FilterTokenRequest& request)
{
- String string = request.sourceTracker.sourceForToken(request.token);
+ String string = request.sourceTracker.source(request.token);
size_t startPosition = 0;
size_t endPosition = string.length();
size_t foundPosition = notFound;
+ size_t lastNonSpacePosition = notFound;
// Skip over initial comments to find start of code.
while (startPosition < endPosition) {
@@ -657,30 +672,39 @@ String XSSAuditor::decodedSnippetForJavaScript(const FilterTokenRequest& request
String result;
while (startPosition < endPosition && !result.length()) {
- // Stop at next comment (using the same rules as above for SVG/XML vs HTML), when we
- // encounter a comma, or when we exceed the maximum length target. The comma rule
- // covers a common parameter concatenation case performed by some webservers.
- // After hitting the length target, we can only stop at a point where we know we are
- // not in the middle of a %-escape sequence. For the sake of simplicity, approximate
- // not stopping inside a (possibly multiply encoded) %-esacpe sequence by breaking on
- // whitespace only. We should have enough text in these cases to avoid false positives.
+ // Stop at next comment (using the same rules as above for SVG/XML vs HTML), when we encounter a comma,
+ // when we hit an opening <script> tag, or when we exceed the maximum length target. The comma rule
+ // covers a common parameter concatenation case performed by some web servers.
+ lastNonSpacePosition = notFound;
for (foundPosition = startPosition; foundPosition < endPosition; foundPosition++) {
if (!request.shouldAllowCDATA) {
- if (startsSingleLineCommentAt(string, foundPosition) || startsMultiLineCommentAt(string, foundPosition)) {
- foundPosition += 2;
- break;
- }
- if (startsHTMLCommentAt(string, foundPosition)) {
- foundPosition += 4;
+ if (startsSingleLineCommentAt(string, foundPosition)
+ || startsMultiLineCommentAt(string, foundPosition)
+ || startsHTMLCommentAt(string, foundPosition)) {
break;
}
}
- if (string[foundPosition] == ',' || (foundPosition > startPosition + kMaximumFragmentLengthTarget && isHTMLSpace(string[foundPosition]))) {
+ if (string[foundPosition] == ',')
+ break;
+
+ if (lastNonSpacePosition != notFound && startsOpeningScriptTagAt(string, foundPosition)) {
+ foundPosition = lastNonSpacePosition + 1;
break;
}
+ if (foundPosition > startPosition + kMaximumFragmentLengthTarget) {
+ // After hitting the length target, we can only stop at a point where we know we are
+ // not in the middle of a %-escape sequence. For the sake of simplicity, approximate
+ // not stopping inside a (possibly multiply encoded) %-escape sequence by breaking on
+ // whitespace only. We should have enough text in these cases to avoid false positives.
+ if (isHTMLSpace(string[foundPosition]))
+ break;
+ }
+
+ if (!isHTMLSpace(string[foundPosition]))
+ lastNonSpacePosition = foundPosition;
}
- result = fullyDecodeString(string.substring(startPosition, foundPosition - startPosition), m_encoding);
+ result = canonicalize(string.substring(startPosition, foundPosition - startPosition), TruncationStyle::None);
startPosition = foundPosition + 1;
}
return result;
@@ -718,12 +742,4 @@ bool XSSAuditor::isLikelySafeResource(const String& url)
return (m_documentURL.host() == resourceURL.host() && resourceURL.query().isEmpty());
}
-bool XSSAuditor::isSafeToSendToAnotherThread() const
-{
- return m_documentURL.isSafeToSendToAnotherThread()
- && m_decodedURL.isSafeToSendToAnotherThread()
- && m_decodedHTTPBody.isSafeToSendToAnotherThread()
- && m_cachedDecodedSnippet.isSafeToSendToAnotherThread();
-}
-
} // namespace WebCore
diff --git a/Source/WebCore/html/parser/XSSAuditor.h b/Source/WebCore/html/parser/XSSAuditor.h
index 28fe3dec9..dc82add7c 100644
--- a/Source/WebCore/html/parser/XSSAuditor.h
+++ b/Source/WebCore/html/parser/XSSAuditor.h
@@ -23,15 +23,13 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef XSSAuditor_h
-#define XSSAuditor_h
+#pragma once
#include "HTMLToken.h"
#include "HTTPParsers.h"
#include "URL.h"
#include "SuffixTree.h"
#include "TextEncoding.h"
-#include <wtf/PassOwnPtr.h>
namespace WebCore {
@@ -62,7 +60,6 @@ public:
void initForFragment();
std::unique_ptr<XSSInfo> filterToken(const FilterTokenRequest&);
- bool isSafeToSendToAnotherThread() const;
private:
static const size_t kMaximumFragmentLengthTarget = 100;
@@ -72,7 +69,8 @@ private:
Initialized
};
- enum AttributeKind {
+ enum class TruncationStyle {
+ None,
NormalAttribute,
SrcLikeAttribute,
ScriptLikeAttribute
@@ -86,7 +84,7 @@ private:
bool filterParamToken(const FilterTokenRequest&);
bool filterEmbedToken(const FilterTokenRequest&);
bool filterAppletToken(const FilterTokenRequest&);
- bool filterIframeToken(const FilterTokenRequest&);
+ bool filterFrameToken(const FilterTokenRequest&);
bool filterMetaToken(const FilterTokenRequest&);
bool filterBaseToken(const FilterTokenRequest&);
bool filterFormToken(const FilterTokenRequest&);
@@ -94,12 +92,12 @@ private:
bool filterButtonToken(const FilterTokenRequest&);
bool eraseDangerousAttributesIfInjected(const FilterTokenRequest&);
- bool eraseAttributeIfInjected(const FilterTokenRequest&, const QualifiedName&, const String& replacementValue = String(), AttributeKind treatment = NormalAttribute);
+ bool eraseAttributeIfInjected(const FilterTokenRequest&, const QualifiedName&, const String& replacementValue = String(), TruncationStyle = TruncationStyle::NormalAttribute);
- String decodedSnippetForToken(const HTMLToken&);
- String decodedSnippetForName(const FilterTokenRequest&);
- String decodedSnippetForAttribute(const FilterTokenRequest&, const HTMLToken::Attribute&, AttributeKind treatment = NormalAttribute);
- String decodedSnippetForJavaScript(const FilterTokenRequest&);
+ String canonicalizedSnippetForTagName(const FilterTokenRequest&);
+ String canonicalizedSnippetForJavaScript(const FilterTokenRequest&);
+ String snippetFromAttribute(const FilterTokenRequest&, const HTMLToken::Attribute&);
+ String canonicalize(const String&, TruncationStyle);
bool isContainedInRequest(const String&);
bool isLikelySafeResource(const String& url);
@@ -107,8 +105,7 @@ private:
URL m_documentURL;
bool m_isEnabled;
- ContentSecurityPolicy::ReflectedXSSDisposition m_xssProtection;
- bool m_didSendValidCSPHeader;
+ XSSProtectionDisposition m_xssProtection;
bool m_didSendValidXSSProtectionHeader;
String m_decodedURL;
@@ -116,11 +113,9 @@ private:
std::unique_ptr<SuffixTree<ASCIICodebook>> m_decodedHTTPBodySuffixTree;
State m_state;
- String m_cachedDecodedSnippet;
+ bool m_wasScriptTagFoundInRequest { false };
unsigned m_scriptTagNestingLevel;
TextEncoding m_encoding;
};
-}
-
-#endif
+} // namespace WebCore
diff --git a/Source/WebCore/html/parser/XSSAuditorDelegate.cpp b/Source/WebCore/html/parser/XSSAuditorDelegate.cpp
index d06069b31..2cbe9bbb8 100644
--- a/Source/WebCore/html/parser/XSSAuditorDelegate.cpp
+++ b/Source/WebCore/html/parser/XSSAuditorDelegate.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2013 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,8 +27,6 @@
#include "config.h"
#include "XSSAuditorDelegate.h"
-#include "Console.h"
-#include "DOMWindow.h"
#include "Document.h"
#include "DocumentLoader.h"
#include "FormData.h"
@@ -36,7 +35,6 @@
#include "FrameLoaderClient.h"
#include "HTMLParserIdioms.h"
#include "PingLoader.h"
-#include "SecurityOrigin.h"
#include <inspector/InspectorValues.h>
#include <wtf/text/StringBuilder.h>
#include <wtf/text/CString.h>
@@ -47,49 +45,46 @@ namespace WebCore {
XSSAuditorDelegate::XSSAuditorDelegate(Document& document)
: m_document(document)
- , m_didSendNotifications(false)
{
ASSERT(isMainThread());
}
-static inline String buildConsoleError(const XSSInfo& xssInfo, const String& url)
+static inline String buildConsoleError(const XSSInfo& xssInfo)
{
StringBuilder message;
- message.append("The XSS Auditor ");
+ message.appendLiteral("The XSS Auditor ");
message.append(xssInfo.m_didBlockEntirePage ? "blocked access to" : "refused to execute a script in");
- message.append(" '");
- message.append(url);
- message.append("' because ");
+ message.appendLiteral(" '");
+ message.append(xssInfo.m_originalURL);
+ message.appendLiteral("' because ");
message.append(xssInfo.m_didBlockEntirePage ? "the source code of a script" : "its source code");
- message.append(" was found within the request.");
+ message.appendLiteral(" was found within the request.");
- if (xssInfo.m_didSendCSPHeader)
- message.append(" The server sent a 'Content-Security-Policy' header requesting this behavior.");
- else if (xssInfo.m_didSendXSSProtectionHeader)
- message.append(" The server sent an 'X-XSS-Protection' header requesting this behavior.");
+ if (xssInfo.m_didSendXSSProtectionHeader)
+ message.appendLiteral(" The server sent an 'X-XSS-Protection' header requesting this behavior.");
else
- message.append(" The auditor was enabled as the server sent neither an 'X-XSS-Protection' nor 'Content-Security-Policy' header.");
+ message.appendLiteral(" The auditor was enabled because the server did not send an 'X-XSS-Protection' header.");
return message.toString();
}
-PassRefPtr<FormData> XSSAuditorDelegate::generateViolationReport()
+Ref<FormData> XSSAuditorDelegate::generateViolationReport(const XSSInfo& xssInfo)
{
ASSERT(isMainThread());
- FrameLoader& frameLoader = m_document.frame()->loader();
+ auto& frameLoader = m_document.frame()->loader();
String httpBody;
if (frameLoader.documentLoader()) {
- if (FormData* formData = frameLoader.documentLoader()->originalRequest().httpBody())
+ if (auto* formData = frameLoader.documentLoader()->originalRequest().httpBody())
httpBody = formData->flattenToString();
}
- RefPtr<InspectorObject> reportDetails = InspectorObject::create();
- reportDetails->setString("request-url", m_document.url().string());
+ auto reportDetails = InspectorObject::create();
+ reportDetails->setString("request-url", xssInfo.m_originalURL);
reportDetails->setString("request-body", httpBody);
- RefPtr<InspectorObject> reportObject = InspectorObject::create();
- reportObject->setObject("xss-report", reportDetails.release());
+ auto reportObject = InspectorObject::create();
+ reportObject->setObject("xss-report", WTFMove(reportDetails));
return FormData::create(reportObject->toJSONString().utf8().data());
}
@@ -98,7 +93,7 @@ void XSSAuditorDelegate::didBlockScript(const XSSInfo& xssInfo)
{
ASSERT(isMainThread());
- m_document.addConsoleMessage(JSMessageSource, ErrorMessageLevel, buildConsoleError(xssInfo, m_document.url().string()));
+ m_document.addConsoleMessage(MessageSource::JS, MessageLevel::Error, buildConsoleError(xssInfo));
FrameLoader& frameLoader = m_document.frame()->loader();
if (xssInfo.m_didBlockEntirePage)
@@ -110,11 +105,11 @@ void XSSAuditorDelegate::didBlockScript(const XSSInfo& xssInfo)
frameLoader.client().didDetectXSS(m_document.url(), xssInfo.m_didBlockEntirePage);
if (!m_reportURL.isEmpty())
- PingLoader::sendViolationReport(m_document.frame(), m_reportURL, generateViolationReport());
+ PingLoader::sendViolationReport(*m_document.frame(), m_reportURL, generateViolationReport(xssInfo), ViolationReportType::XSSAuditor);
}
if (xssInfo.m_didBlockEntirePage)
- m_document.frame()->navigationScheduler().scheduleLocationChange(m_document.securityOrigin(), SecurityOrigin::urlWithUniqueSecurityOrigin(), String());
+ m_document.frame()->navigationScheduler().schedulePageBlock(m_document);
}
} // namespace WebCore
diff --git a/Source/WebCore/html/parser/XSSAuditorDelegate.h b/Source/WebCore/html/parser/XSSAuditorDelegate.h
index e12760e32..67a32ed93 100644
--- a/Source/WebCore/html/parser/XSSAuditorDelegate.h
+++ b/Source/WebCore/html/parser/XSSAuditorDelegate.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2013 Google, Inc. All Rights Reserved.
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -23,13 +24,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef XSSAuditorDelegate_h
-#define XSSAuditorDelegate_h
+#pragma once
#include "URL.h"
-#include <wtf/OwnPtr.h>
-#include <wtf/PassOwnPtr.h>
-#include <wtf/Vector.h>
#include <wtf/text/TextPosition.h>
namespace WebCore {
@@ -37,23 +34,25 @@ namespace WebCore {
class Document;
class FormData;
+// FIXME: Should change into a struct.
+// FIXME: Should return by value instead of using a unique_ptr.
class XSSInfo {
+ WTF_MAKE_FAST_ALLOCATED;
public:
- XSSInfo(bool didBlockEntirePage, bool didSendXSSProtectionHeader, bool didSendCSPHeader)
- : m_didBlockEntirePage(didBlockEntirePage)
+ XSSInfo(const String& originalURL, bool didBlockEntirePage, bool didSendXSSProtectionHeader)
+ : m_originalURL(originalURL.isolatedCopy())
+ , m_didBlockEntirePage(didBlockEntirePage)
, m_didSendXSSProtectionHeader(didSendXSSProtectionHeader)
- , m_didSendCSPHeader(didSendCSPHeader)
{
}
+ String m_originalURL;
bool m_didBlockEntirePage;
bool m_didSendXSSProtectionHeader;
- bool m_didSendCSPHeader;
TextPosition m_textPosition;
};
class XSSAuditorDelegate {
- WTF_MAKE_NONCOPYABLE(XSSAuditorDelegate);
public:
explicit XSSAuditorDelegate(Document&);
@@ -61,13 +60,11 @@ public:
void setReportURL(const URL& url) { m_reportURL = url; }
private:
- PassRefPtr<FormData> generateViolationReport();
+ Ref<FormData> generateViolationReport(const XSSInfo&);
Document& m_document;
- bool m_didSendNotifications;
+ bool m_didSendNotifications { false };
URL m_reportURL;
};
-}
-
-#endif
+} // namespace WebCore