1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 10:38:11 +00:00

LibWeb: Implement more of the foster parenting algorithm in the parser

This commit is contained in:
Andreas Kling 2020-06-21 17:00:55 +02:00
parent 213e2793bd
commit 966bc05fef
4 changed files with 58 additions and 12 deletions

View file

@ -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); 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(); auto& target = current_node();
if (m_foster_parenting) { 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)) {
TODO(); // 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; return { target, nullptr };
} }
NonnullRefPtr<Element> HTMLDocumentParser::create_element_for(HTMLToken& token) 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 adjusted_insertion_location = find_appropriate_place_for_inserting_node();
auto element = create_element_for(token); auto element = create_element_for(token);
// FIXME: Check if it's possible to insert `element` at `adjusted_insertion_location` // 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); m_stack_of_open_elements.push(element);
return element; return element;
} }
@ -332,7 +338,7 @@ void HTMLDocumentParser::insert_comment(HTMLToken& token)
{ {
auto data = token.m_comment_or_character.data.to_string(); auto data = token.m_comment_or_character.data.to_string();
auto adjusted_insertion_location = find_appropriate_place_for_inserting_node(); 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) 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) { if (token.is_start_tag() && token.tag_name() == HTML::TagNames::noscript && !m_scripting_enabled) {
insert_html_element(token); insert_html_element(token);
m_insertion_mode = InsertionMode::InHeadNoscript; m_insertion_mode = InsertionMode::InHeadNoscript;
return;
} }
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::script) { if (token.is_start_tag() && token.tag_name() == HTML::TagNames::script) {
@ -404,7 +411,7 @@ void HTMLDocumentParser::handle_in_head(HTMLToken& token)
TODO(); 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_stack_of_open_elements.push(element);
m_tokenizer.switch_to({}, HTMLTokenizer::State::ScriptData); m_tokenizer.switch_to({}, HTMLTokenizer::State::ScriptData);
m_original_insertion_mode = m_insertion_mode; 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() Text* HTMLDocumentParser::find_character_insertion_node()
{ {
auto adjusted_insertion_location = find_appropriate_place_for_inserting_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; return nullptr;
if (adjusted_insertion_location->last_child() && adjusted_insertion_location->last_child()->is_text()) if (adjusted_insertion_location.parent->last_child() && adjusted_insertion_location.parent->last_child()->is_text())
return to<Text>(adjusted_insertion_location->last_child()); return to<Text>(adjusted_insertion_location.parent->last_child());
auto new_text_node = adopt(*new Text(document(), "")); 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; 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_) { if (token.is_end_tag() && token.tag_name() == HTML::TagNames::template_) {
process_using_the_rules_for(InsertionMode::InHead, token); 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)) { 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(); PARSE_ERROR();
insert_html_element(token); insert_html_element(token);
return;
} }
if (token.is_start_tag() && token.tag_name().is_one_of(HTML::TagNames::rp, HTML::TagNames::rt)) { 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(); PARSE_ERROR();
insert_html_element(token); insert_html_element(token);
return;
} }
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::math) { if (token.is_start_tag() && token.tag_name() == HTML::TagNames::math) {

View file

@ -110,7 +110,14 @@ private:
void generate_implied_end_tags(const FlyString& exception = {}); void generate_implied_end_tags(const FlyString& exception = {});
bool stack_of_open_elements_has_element_with_tag_name_in_scope(const FlyString& tag_name); bool stack_of_open_elements_has_element_with_tag_name_in_scope(const FlyString& tag_name);
NonnullRefPtr<Element> create_element_for(HTMLToken&); 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(); Text* find_character_insertion_node();
void flush_character_insertions(); void flush_character_insertions();
RefPtr<Element> insert_html_element(HTMLToken&); RefPtr<Element> insert_html_element(HTMLToken&);

View file

@ -140,4 +140,27 @@ Element* StackOfOpenElements::topmost_special_node_below(const Element& formatti
return found_element; 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;
}
} }

View file

@ -65,6 +65,9 @@ public:
Element* topmost_special_node_below(const Element&); Element* topmost_special_node_below(const Element&);
Element* last_element_with_tag_name(const FlyString&);
Element* element_before(const Element&);
private: private:
bool has_in_scope_impl(const FlyString& tag_name, const Vector<FlyString>&) const; 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; bool has_in_scope_impl(const Element& target_node, const Vector<FlyString>&) const;