diff --git a/Libraries/LibWeb/Parser/HTMLDocumentParser.cpp b/Libraries/LibWeb/Parser/HTMLDocumentParser.cpp
index 821ee3fc4e..e524fe0edd 100644
--- a/Libraries/LibWeb/Parser/HTMLDocumentParser.cpp
+++ b/Libraries/LibWeb/Parser/HTMLDocumentParser.cpp
@@ -817,7 +817,16 @@ void HTMLDocumentParser::handle_in_body(HTMLToken& token)
}
if (token.is_start_tag() && token.tag_name() == "form") {
- TODO();
+ if (m_form_element && m_stack_of_open_elements.contains("template")) {
+ PARSE_ERROR();
+ return;
+ }
+ if (m_stack_of_open_elements.has_in_button_scope("p"))
+ close_a_p_element();
+ auto element = insert_html_element(token);
+ if (!m_stack_of_open_elements.contains("template"))
+ m_form_element = to(*element);
+ return;
}
if (token.is_start_tag() && token.tag_name() == "li") {
@@ -887,7 +896,22 @@ void HTMLDocumentParser::handle_in_body(HTMLToken& token)
}
if (token.is_end_tag() && token.tag_name() == "form") {
- TODO();
+ if (!m_stack_of_open_elements.contains("template")) {
+ auto node = m_form_element;
+ m_form_element = nullptr;
+ if (!node || m_stack_of_open_elements.has_in_scope(*node)) {
+ PARSE_ERROR();
+ return;
+ }
+ generate_implied_end_tags();
+ if (¤t_node() != node) {
+ PARSE_ERROR();
+ }
+ m_stack_of_open_elements.elements().remove_first_matching([&](auto& entry) { return entry.ptr() == node.ptr(); });
+ } else {
+ TODO();
+ }
+ return;
}
if (token.is_end_tag() && token.tag_name() == "p") {
diff --git a/Libraries/LibWeb/Parser/StackOfOpenElements.cpp b/Libraries/LibWeb/Parser/StackOfOpenElements.cpp
index 807fc40c0e..5048b83fc8 100644
--- a/Libraries/LibWeb/Parser/StackOfOpenElements.cpp
+++ b/Libraries/LibWeb/Parser/StackOfOpenElements.cpp
@@ -103,6 +103,15 @@ bool StackOfOpenElements::contains(const Element& element) const
return false;
}
+bool StackOfOpenElements::contains(const FlyString& tag_name) const
+{
+ for (auto& element_on_stack : m_elements) {
+ if (element_on_stack.tag_name() == tag_name)
+ return true;
+ }
+ return false;
+}
+
void StackOfOpenElements::pop_until_an_element_with_tag_name_has_been_popped(const FlyString& tag_name)
{
while (m_elements.last().tag_name() != tag_name)
diff --git a/Libraries/LibWeb/Parser/StackOfOpenElements.h b/Libraries/LibWeb/Parser/StackOfOpenElements.h
index d6dbd18d27..6fb4455def 100644
--- a/Libraries/LibWeb/Parser/StackOfOpenElements.h
+++ b/Libraries/LibWeb/Parser/StackOfOpenElements.h
@@ -55,6 +55,7 @@ public:
bool has_in_scope(const Element&) const;
bool contains(const Element&) const;
+ bool contains(const FlyString& tag_name) const;
const NonnullRefPtrVector& elements() const { return m_elements; }
NonnullRefPtrVector& elements() { return m_elements; }