diff --git a/Libraries/LibWeb/Parser/HTMLDocumentParser.cpp b/Libraries/LibWeb/Parser/HTMLDocumentParser.cpp
index 08200a38f0..026f8f0733 100644
--- a/Libraries/LibWeb/Parser/HTMLDocumentParser.cpp
+++ b/Libraries/LibWeb/Parser/HTMLDocumentParser.cpp
@@ -400,10 +400,43 @@ void HTMLDocumentParser::handle_after_after_body(HTMLToken& token)
void HTMLDocumentParser::reconstruct_the_active_formatting_elements()
{
+ // FIXME: This needs to care about "markers"
+
if (m_list_of_active_formatting_elements.is_empty())
return;
- ASSERT_NOT_REACHED();
+ if (m_stack_of_open_elements.contains(m_list_of_active_formatting_elements.last()))
+ return;
+
+ ssize_t index = m_list_of_active_formatting_elements.size() - 1;
+ RefPtr entry = m_list_of_active_formatting_elements.at(index);
+
+Rewind:
+ if (m_list_of_active_formatting_elements.size() == 1) {
+ goto Create;
+ }
+
+ --index;
+ entry = m_list_of_active_formatting_elements.at(index);
+
+ if (!m_stack_of_open_elements.contains(*entry))
+ goto Rewind;
+
+Advance:
+ ++index;
+ entry = m_list_of_active_formatting_elements.at(index);
+
+Create:
+ // FIXME: Hold on to the real token!
+ HTMLToken fake_token;
+ fake_token.m_type = HTMLToken::Type::StartTag;
+ fake_token.m_tag.tag_name.append(entry->tag_name());
+ auto new_element = insert_html_element(fake_token);
+
+ m_list_of_active_formatting_elements.ptr_at(index) = *new_element;
+
+ if (index != (ssize_t)m_list_of_active_formatting_elements.size() - 1)
+ goto Advance;
}
void HTMLDocumentParser::handle_in_body(HTMLToken& token)
@@ -535,6 +568,27 @@ void HTMLDocumentParser::handle_in_body(HTMLToken& token)
return;
}
+ if (token.is_end_tag()) {
+ RefPtr node;
+ for (ssize_t i = m_stack_of_open_elements.elements().size() - 1; i >= 0; --i) {
+ node = m_stack_of_open_elements.elements()[i];
+ if (node->tag_name() == token.tag_name()) {
+ generate_implied_end_tags(token.tag_name());
+ if (node != current_node()) {
+ // It's a parse error
+ TODO();
+ }
+ while (¤t_node() != node) {
+ m_stack_of_open_elements.pop();
+ }
+ m_stack_of_open_elements.pop();
+ break;
+ }
+ // FIXME: Handle special elements!
+ }
+ return;
+ }
+
ASSERT_NOT_REACHED();
}
diff --git a/Libraries/LibWeb/Parser/StackOfOpenElements.cpp b/Libraries/LibWeb/Parser/StackOfOpenElements.cpp
index 1c99624446..506bc88d00 100644
--- a/Libraries/LibWeb/Parser/StackOfOpenElements.cpp
+++ b/Libraries/LibWeb/Parser/StackOfOpenElements.cpp
@@ -33,4 +33,13 @@ bool StackOfOpenElements::has_in_button_scope(const FlyString& tag_name) const
return has_in_scope_impl(tag_name, list);
}
+bool StackOfOpenElements::contains(const Element& element) const
+{
+ for (auto& element_on_stack : m_elements) {
+ if (&element == &element_on_stack)
+ return true;
+ }
+ return false;
+}
+
}
diff --git a/Libraries/LibWeb/Parser/StackOfOpenElements.h b/Libraries/LibWeb/Parser/StackOfOpenElements.h
index 98ac36434b..8403f36158 100644
--- a/Libraries/LibWeb/Parser/StackOfOpenElements.h
+++ b/Libraries/LibWeb/Parser/StackOfOpenElements.h
@@ -47,6 +47,10 @@ public:
bool has_in_scope(const FlyString& tag_name) const;
bool has_in_button_scope(const FlyString& tag_name) const;
+ bool contains(const Element&) const;
+
+ const NonnullRefPtrVector& elements() const { return m_elements; }
+
private:
bool has_in_scope_impl(const FlyString& tag_name, const Vector&) const;