summaryrefslogtreecommitdiff
path: root/Libraries
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-06-21 17:00:55 +0200
committerAndreas Kling <kling@serenityos.org>2020-06-21 17:42:00 +0200
commit966bc05fefe526168b4cd52a1b4c15ec6d5d810e (patch)
tree3168058ffb5c4d28c6aef5344ec2edb0587c3986 /Libraries
parent213e2793bd4fcfc6fec2b32ce2039dd05bba64cd (diff)
downloadserenity-966bc05fefe526168b4cd52a1b4c15ec6d5d810e.zip
LibWeb: Implement more of the foster parenting algorithm in the parser
Diffstat (limited to 'Libraries')
-rw-r--r--Libraries/LibWeb/Parser/HTMLDocumentParser.cpp37
-rw-r--r--Libraries/LibWeb/Parser/HTMLDocumentParser.h9
-rw-r--r--Libraries/LibWeb/Parser/StackOfOpenElements.cpp23
-rw-r--r--Libraries/LibWeb/Parser/StackOfOpenElements.h3
4 files changed, 59 insertions, 13 deletions
diff --git a/Libraries/LibWeb/Parser/HTMLDocumentParser.cpp b/Libraries/LibWeb/Parser/HTMLDocumentParser.cpp
index 8bee4459f3..9019461bce 100644
--- a/Libraries/LibWeb/Parser/HTMLDocumentParser.cpp
+++ b/Libraries/LibWeb/Parser/HTMLDocumentParser.cpp
@@ -253,13 +253,19 @@ Element& HTMLDocumentParser::node_before_current_node()
return m_stack_of_open_elements.elements().at(m_stack_of_open_elements.elements().size() - 2);
}
-RefPtr<Node> HTMLDocumentParser::find_appropriate_place_for_inserting_node()
+HTMLDocumentParser::AdjustedInsertionLocation HTMLDocumentParser::find_appropriate_place_for_inserting_node()
{
auto& target = current_node();
- if (m_foster_parenting) {
- TODO();
- }
- return target;
+ if (m_foster_parenting && target.tag_name().is_one_of(HTML::TagNames::table, HTML::TagNames::tbody, HTML::TagNames::tfoot, HTML::TagNames::thead, HTML::TagNames::tr)) {
+ // FIXME: There's a bunch of steps for <template> elements here.
+ auto last_table = m_stack_of_open_elements.last_element_with_tag_name(HTML::TagNames::table);
+ if (!last_table)
+ return { m_stack_of_open_elements.elements().first(), nullptr };
+ if (last_table->parent_node())
+ return { last_table->parent_node(), last_table };
+ return { m_stack_of_open_elements.element_before(*last_table), nullptr };
+ }
+ return { target, nullptr };
}
NonnullRefPtr<Element> HTMLDocumentParser::create_element_for(HTMLToken& token)
@@ -276,7 +282,7 @@ RefPtr<Element> HTMLDocumentParser::insert_html_element(HTMLToken& token)
auto adjusted_insertion_location = find_appropriate_place_for_inserting_node();
auto element = create_element_for(token);
// FIXME: Check if it's possible to insert `element` at `adjusted_insertion_location`
- adjusted_insertion_location->append_child(element);
+ adjusted_insertion_location.parent->insert_before(element, adjusted_insertion_location.insert_before_sibling);
m_stack_of_open_elements.push(element);
return element;
}
@@ -332,7 +338,7 @@ void HTMLDocumentParser::insert_comment(HTMLToken& token)
{
auto data = token.m_comment_or_character.data.to_string();
auto adjusted_insertion_location = find_appropriate_place_for_inserting_node();
- adjusted_insertion_location->append_child(adopt(*new Comment(document(), data)));
+ adjusted_insertion_location.parent->insert_before(adopt(*new Comment(document(), data)), adjusted_insertion_location.insert_before_sibling);
}
void HTMLDocumentParser::handle_in_head(HTMLToken& token)
@@ -387,6 +393,7 @@ void HTMLDocumentParser::handle_in_head(HTMLToken& token)
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::noscript && !m_scripting_enabled) {
insert_html_element(token);
m_insertion_mode = InsertionMode::InHeadNoscript;
+ return;
}
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::script) {
@@ -404,7 +411,7 @@ void HTMLDocumentParser::handle_in_head(HTMLToken& token)
TODO();
}
- adjusted_insertion_location->append_child(element, false);
+ adjusted_insertion_location.parent->insert_before(element, adjusted_insertion_location.insert_before_sibling, false);
m_stack_of_open_elements.push(element);
m_tokenizer.switch_to({}, HTMLTokenizer::State::ScriptData);
m_original_insertion_mode = m_insertion_mode;
@@ -495,12 +502,15 @@ void HTMLDocumentParser::parse_generic_raw_text_element(HTMLToken& token)
Text* HTMLDocumentParser::find_character_insertion_node()
{
auto adjusted_insertion_location = find_appropriate_place_for_inserting_node();
- if (adjusted_insertion_location->is_document())
+ if (adjusted_insertion_location.insert_before_sibling) {
+ TODO();
+ }
+ if (adjusted_insertion_location.parent->is_document())
return nullptr;
- if (adjusted_insertion_location->last_child() && adjusted_insertion_location->last_child()->is_text())
- return to<Text>(adjusted_insertion_location->last_child());
+ if (adjusted_insertion_location.parent->last_child() && adjusted_insertion_location.parent->last_child()->is_text())
+ return to<Text>(adjusted_insertion_location.parent->last_child());
auto new_text_node = adopt(*new Text(document(), ""));
- adjusted_insertion_location->append_child(new_text_node);
+ adjusted_insertion_location.parent->append_child(new_text_node);
return new_text_node;
}
@@ -577,6 +587,7 @@ void HTMLDocumentParser::handle_after_head(HTMLToken& token)
if (token.is_end_tag() && token.tag_name() == HTML::TagNames::template_) {
process_using_the_rules_for(InsertionMode::InHead, token);
+ return;
}
if (token.is_end_tag() && token.tag_name().is_one_of(HTML::TagNames::body, HTML::TagNames::html, HTML::TagNames::br)) {
@@ -1423,6 +1434,7 @@ void HTMLDocumentParser::handle_in_body(HTMLToken& token)
PARSE_ERROR();
insert_html_element(token);
+ return;
}
if (token.is_start_tag() && token.tag_name().is_one_of(HTML::TagNames::rp, HTML::TagNames::rt)) {
@@ -1433,6 +1445,7 @@ void HTMLDocumentParser::handle_in_body(HTMLToken& token)
PARSE_ERROR();
insert_html_element(token);
+ return;
}
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::math) {
diff --git a/Libraries/LibWeb/Parser/HTMLDocumentParser.h b/Libraries/LibWeb/Parser/HTMLDocumentParser.h
index a3c8153935..02f8b3c900 100644
--- a/Libraries/LibWeb/Parser/HTMLDocumentParser.h
+++ b/Libraries/LibWeb/Parser/HTMLDocumentParser.h
@@ -110,7 +110,14 @@ private:
void generate_implied_end_tags(const FlyString& exception = {});
bool stack_of_open_elements_has_element_with_tag_name_in_scope(const FlyString& tag_name);
NonnullRefPtr<Element> create_element_for(HTMLToken&);
- RefPtr<Node> find_appropriate_place_for_inserting_node();
+
+ struct AdjustedInsertionLocation {
+ RefPtr<Node> parent;
+ RefPtr<Node> insert_before_sibling;
+ };
+
+ AdjustedInsertionLocation find_appropriate_place_for_inserting_node();
+
Text* find_character_insertion_node();
void flush_character_insertions();
RefPtr<Element> insert_html_element(HTMLToken&);
diff --git a/Libraries/LibWeb/Parser/StackOfOpenElements.cpp b/Libraries/LibWeb/Parser/StackOfOpenElements.cpp
index f3c3925870..d27c0f95c9 100644
--- a/Libraries/LibWeb/Parser/StackOfOpenElements.cpp
+++ b/Libraries/LibWeb/Parser/StackOfOpenElements.cpp
@@ -140,4 +140,27 @@ Element* StackOfOpenElements::topmost_special_node_below(const Element& formatti
return found_element;
}
+Element* StackOfOpenElements::last_element_with_tag_name(const FlyString& tag_name)
+{
+ for (ssize_t i = m_elements.size() - 1; i >= 0; --i) {
+ auto& element = m_elements[i];
+ if (element.tag_name() == tag_name)
+ return &element;
+ }
+ return nullptr;
+}
+
+Element* StackOfOpenElements::element_before(const Element& target)
+{
+ bool found_target = false;
+ for (ssize_t i = m_elements.size() - 1; i >= 0; --i) {
+ auto& element = m_elements[i];
+ if (&element == &target) {
+ found_target = true;
+ } else if (found_target)
+ return &element;
+ }
+ return nullptr;
+}
+
}
diff --git a/Libraries/LibWeb/Parser/StackOfOpenElements.h b/Libraries/LibWeb/Parser/StackOfOpenElements.h
index 9e5076102f..8b8397208d 100644
--- a/Libraries/LibWeb/Parser/StackOfOpenElements.h
+++ b/Libraries/LibWeb/Parser/StackOfOpenElements.h
@@ -65,6 +65,9 @@ public:
Element* topmost_special_node_below(const Element&);
+ Element* last_element_with_tag_name(const FlyString&);
+ Element* element_before(const Element&);
+
private:
bool has_in_scope_impl(const FlyString& tag_name, const Vector<FlyString>&) const;
bool has_in_scope_impl(const Element& target_node, const Vector<FlyString>&) const;