diff options
author | Andreas Kling <kling@serenityos.org> | 2020-06-21 17:00:55 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-06-21 17:42:00 +0200 |
commit | 966bc05fefe526168b4cd52a1b4c15ec6d5d810e (patch) | |
tree | 3168058ffb5c4d28c6aef5344ec2edb0587c3986 /Libraries | |
parent | 213e2793bd4fcfc6fec2b32ce2039dd05bba64cd (diff) | |
download | serenity-966bc05fefe526168b4cd52a1b4c15ec6d5d810e.zip |
LibWeb: Implement more of the foster parenting algorithm in the parser
Diffstat (limited to 'Libraries')
-rw-r--r-- | Libraries/LibWeb/Parser/HTMLDocumentParser.cpp | 37 | ||||
-rw-r--r-- | Libraries/LibWeb/Parser/HTMLDocumentParser.h | 9 | ||||
-rw-r--r-- | Libraries/LibWeb/Parser/StackOfOpenElements.cpp | 23 | ||||
-rw-r--r-- | Libraries/LibWeb/Parser/StackOfOpenElements.h | 3 |
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; |