mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 11:18:11 +00:00
LibWeb: Implement more of the foster parenting algorithm in the parser
This commit is contained in:
parent
213e2793bd
commit
966bc05fef
4 changed files with 58 additions and 12 deletions
|
@ -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();
|
||||
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;
|
||||
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) {
|
||||
|
|
|
@ -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&);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue