LibWeb: Make HTML parser "current node" APIs return nullable pointer

It's actually possible for there to be no adjusted current node, when
the stack of open elements is empty. This was covered by one of the WPT
parsing tests.
This commit is contained in:
Andreas Kling 2024-11-03 19:50:13 +01:00 committed by Andreas Kling
commit 64747c0397
Notes: github-actions[bot] 2024-11-03 19:33:21 +00:00
5 changed files with 117 additions and 78 deletions

View file

@ -19,7 +19,6 @@ Text/input/Worker/Worker-performance.html
Text/input/Worker/Worker-postMessage-transfer.html
Text/input/wpt-import/css/css-flexbox/abspos/position-absolute-001.html
Text/input/wpt-import/html/syntax/parsing/html5lib_entities01.html
Text/input/wpt-import/html/syntax/parsing/html5lib_html5test-com.html
Text/input/wpt-import/html/syntax/parsing/html5lib_innerHTML_tests_innerHTML_1.html
Text/input/wpt-import/html/syntax/parsing/html5lib_plain-text-unsafe.html
Text/input/wpt-import/html/syntax/parsing/html5lib_template.html

View file

@ -0,0 +1,34 @@
Summary
Harness status: OK
Rerun
Found 24 tests
24 Pass
Details
Result Test Name MessagePass html5lib_html5test-com.html 71bd5e6b9e907e65295b6d670627e0da4a8a65ed
Pass html5lib_html5test-com.html 32cd504d36a6db3584b716b3681ab4b0741423b3
Pass html5lib_html5test-com.html f0bf0506a2d3e5ca4aa5f14a1f260e405882827e
Pass html5lib_html5test-com.html 666a215d91c4e83d99f4be4caebb67fd65569480
Pass html5lib_html5test-com.html fd2cd459bdc79db754b24bc537758990d392b1fc
Pass html5lib_html5test-com.html 86be28614bf72e24c162d865c04d687447098867
Pass html5lib_html5test-com.html be72b058e5be0f6aef2c442d83c92c0d251fcb7f
Pass html5lib_html5test-com.html ab6e31cf52c8d57d6dfdcaf7165f1abf7bd5e73d
Pass html5lib_html5test-com.html 11240d9b03b14eb515d6a1d1595c5a409830ea38
Pass html5lib_html5test-com.html 809c1bebcded8f43981af902442ff8a2db5d2578
Pass html5lib_html5test-com.html bcbeb84f40e56a642b794d514e97e3ec303d4a79
Pass html5lib_html5test-com.html 1cbb987dd0a35af3a5b2e4fc11eba36a60eba03d
Pass html5lib_html5test-com.html 5b5e75eca2f5c80e1c4d5676254b9891090e288e
Pass html5lib_html5test-com.html 93e966e2edad3297ecb159f3983bdd2dc84f829e
Pass html5lib_html5test-com.html 7a02a2d7ab875dbeedc9a34c6c27b6119bd6d1f0
Pass html5lib_html5test-com.html 46615acdb9dd6231e2a65fed5bcce7e19f086d03
Pass html5lib_html5test-com.html 381de12234a699cbfb775b3ca7c679f357e7403e
Pass html5lib_html5test-com.html 72736fc894b2077928559cc4284a102635cac898
Pass html5lib_html5test-com.html 290d5e7fa9684038411e78c4b0e0ade83150eeea
Pass html5lib_html5test-com.html a5fb9cf46ed215a61d073ae4b7e7477ba49fa5d8
Pass html5lib_html5test-com.html 88dea19243733a9bda26c6f5290d2c4f5bbac157
Pass html5lib_html5test-com.html 9906bb30ae08654f4c67bf6d97040abbca91082d
Pass html5lib_html5test-com.html c6cd25ce02329e4a42b9be9ba35453532fec7599
Pass html5lib_html5test-com.html 81af3f9d6ccc2a1a1a58ace18dd530c544675610

View file

@ -201,11 +201,11 @@ void HTMLParser::run(HTMLTokenizer::StopAtInsertionPoint stop_at_insertion_point
// https://html.spec.whatwg.org/multipage/parsing.html#tree-construction-dispatcher
// As each token is emitted from the tokenizer, the user agent must follow the appropriate steps from the following list, known as the tree construction dispatcher:
if (m_stack_of_open_elements.is_empty()
|| adjusted_current_node().namespace_uri() == Namespace::HTML
|| (is_mathml_text_integration_point(adjusted_current_node()) && token.is_start_tag() && token.tag_name() != MathML::TagNames::mglyph && token.tag_name() != MathML::TagNames::malignmark)
|| (is_mathml_text_integration_point(adjusted_current_node()) && token.is_character())
|| (adjusted_current_node().namespace_uri() == Namespace::MathML && adjusted_current_node().tag_name() == MathML::TagNames::annotation_xml && token.is_start_tag() && token.tag_name() == SVG::TagNames::svg)
|| (is_html_integration_point(adjusted_current_node()) && (token.is_start_tag() || token.is_character()))
|| adjusted_current_node()->namespace_uri() == Namespace::HTML
|| (is_mathml_text_integration_point(*adjusted_current_node()) && token.is_start_tag() && token.tag_name() != MathML::TagNames::mglyph && token.tag_name() != MathML::TagNames::malignmark)
|| (is_mathml_text_integration_point(*adjusted_current_node()) && token.is_character())
|| (adjusted_current_node()->namespace_uri() == Namespace::MathML && adjusted_current_node()->tag_name() == MathML::TagNames::annotation_xml && token.is_start_tag() && token.tag_name() == SVG::TagNames::svg)
|| (is_html_integration_point(*adjusted_current_node()) && (token.is_start_tag() || token.is_character()))
|| token.is_end_of_file()) {
// -> If the stack of open elements is empty
// -> If the adjusted current node is an element in the HTML namespace
@ -608,13 +608,15 @@ AnythingElse:
return;
}
DOM::Element& HTMLParser::current_node()
JS::GCPtr<DOM::Element> HTMLParser::current_node()
{
if (m_stack_of_open_elements.is_empty())
return nullptr;
return m_stack_of_open_elements.current_node();
}
// https://html.spec.whatwg.org/multipage/parsing.html#adjusted-current-node
DOM::Element& HTMLParser::adjusted_current_node()
JS::GCPtr<DOM::Element> HTMLParser::adjusted_current_node()
{
// The adjusted current node is the context element if the parser was created as part of the
// HTML fragment parsing algorithm and the stack of open elements has only one element in it
@ -626,8 +628,10 @@ DOM::Element& HTMLParser::adjusted_current_node()
return current_node();
}
DOM::Element& HTMLParser::node_before_current_node()
JS::GCPtr<DOM::Element> HTMLParser::node_before_current_node()
{
if (m_stack_of_open_elements.elements().size() < 2)
return nullptr;
return *m_stack_of_open_elements.elements().at(m_stack_of_open_elements.elements().size() - 2);
}
@ -635,7 +639,7 @@ DOM::Element& HTMLParser::node_before_current_node()
HTMLParser::AdjustedInsertionLocation HTMLParser::find_appropriate_place_for_inserting_node(JS::GCPtr<DOM::Element> override_target)
{
// 1. If there was an override target specified, then let target be the override target.
auto& target = override_target ? *override_target.ptr() : current_node();
auto& target = override_target ? *override_target.ptr() : *current_node();
HTMLParser::AdjustedInsertionLocation adjusted_insertion_location;
// 2. Determine the adjusted insertion location using the first matching steps from the following list:
@ -986,7 +990,7 @@ void HTMLParser::handle_in_head(HTMLToken& token)
// - the adjusted current node is not the topmost element in the stack of open elements,
if (!shadowrootmode.has_value()
|| !document.allow_declarative_shadow_roots()
|| &adjusted_current_node() == &m_stack_of_open_elements.first()) {
|| adjusted_current_node() == &m_stack_of_open_elements.first()) {
// then insert an HTML element for the token.
(void)insert_html_element(token);
}
@ -994,7 +998,7 @@ void HTMLParser::handle_in_head(HTMLToken& token)
// Otherwise:
else {
// 1. Let declarative shadow host element be adjusted current node.
auto& declarative_shadow_host_element = adjusted_current_node();
auto& declarative_shadow_host_element = *adjusted_current_node();
// 2. Let template be the result of insert a foreign element for template start tag, with HTML namespace and true.
auto template_ = insert_foreign_element(template_start_tag, Namespace::HTML, OnlyAddToElementStack::Yes);
@ -1061,7 +1065,7 @@ void HTMLParser::handle_in_head(HTMLToken& token)
generate_all_implied_end_tags_thoroughly();
// 2. If the current node is not a template element, then this is a parse error.
if (current_node().local_name() != HTML::TagNames::template_)
if (current_node()->local_name() != HTML::TagNames::template_)
log_parse_error();
// 3. Pop elements from the stack of open elements until a template element has been popped from the stack.
@ -1282,20 +1286,20 @@ AnythingElse:
void HTMLParser::generate_implied_end_tags(FlyString const& exception)
{
while (current_node().local_name() != exception && current_node().local_name().is_one_of(HTML::TagNames::dd, HTML::TagNames::dt, HTML::TagNames::li, HTML::TagNames::optgroup, HTML::TagNames::option, HTML::TagNames::p, HTML::TagNames::rb, HTML::TagNames::rp, HTML::TagNames::rt, HTML::TagNames::rtc))
while (current_node()->local_name() != exception && current_node()->local_name().is_one_of(HTML::TagNames::dd, HTML::TagNames::dt, HTML::TagNames::li, HTML::TagNames::optgroup, HTML::TagNames::option, HTML::TagNames::p, HTML::TagNames::rb, HTML::TagNames::rp, HTML::TagNames::rt, HTML::TagNames::rtc))
(void)m_stack_of_open_elements.pop();
}
void HTMLParser::generate_all_implied_end_tags_thoroughly()
{
while (current_node().local_name().is_one_of(HTML::TagNames::caption, HTML::TagNames::colgroup, HTML::TagNames::dd, HTML::TagNames::dt, HTML::TagNames::li, HTML::TagNames::optgroup, HTML::TagNames::option, HTML::TagNames::p, HTML::TagNames::rb, HTML::TagNames::rp, HTML::TagNames::rt, HTML::TagNames::rtc, HTML::TagNames::tbody, HTML::TagNames::td, HTML::TagNames::tfoot, HTML::TagNames::th, HTML::TagNames::thead, HTML::TagNames::tr))
while (current_node()->local_name().is_one_of(HTML::TagNames::caption, HTML::TagNames::colgroup, HTML::TagNames::dd, HTML::TagNames::dt, HTML::TagNames::li, HTML::TagNames::optgroup, HTML::TagNames::option, HTML::TagNames::p, HTML::TagNames::rb, HTML::TagNames::rp, HTML::TagNames::rt, HTML::TagNames::rtc, HTML::TagNames::tbody, HTML::TagNames::td, HTML::TagNames::tfoot, HTML::TagNames::th, HTML::TagNames::thead, HTML::TagNames::tr))
(void)m_stack_of_open_elements.pop();
}
void HTMLParser::close_a_p_element()
{
generate_implied_end_tags(HTML::TagNames::p);
if (current_node().local_name() != HTML::TagNames::p) {
if (current_node()->local_name() != HTML::TagNames::p) {
log_parse_error();
}
m_stack_of_open_elements.pop_until_an_element_with_tag_name_has_been_popped(HTML::TagNames::p);
@ -1429,7 +1433,7 @@ HTMLParser::AdoptionAgencyAlgorithmOutcome HTMLParser::run_the_adoption_agency_a
// 2. If the current node is an HTML element whose tag name is subject,
// and the current node is not in the list of active formatting elements,
// then pop the current node off the stack of open elements, and return.
if (current_node().local_name() == subject && !m_list_of_active_formatting_elements.contains(current_node())) {
if (current_node()->local_name() == subject && !m_list_of_active_formatting_elements.contains(*current_node())) {
(void)m_stack_of_open_elements.pop();
return AdoptionAgencyAlgorithmOutcome::DoNothing;
}
@ -1474,7 +1478,7 @@ HTMLParser::AdoptionAgencyAlgorithmOutcome HTMLParser::run_the_adoption_agency_a
}
// 6. If formatting element is not the current node,
if (formatting_element != &current_node()) {
if (formatting_element != current_node()) {
// this is a parse error. (But do not return.)
log_parse_error();
}
@ -1487,7 +1491,7 @@ HTMLParser::AdoptionAgencyAlgorithmOutcome HTMLParser::run_the_adoption_agency_a
if (!furthest_block) {
// then the UA must first pop all the nodes from the bottom of the stack of open elements,
// from the current node up to and including formatting element,
while (&current_node() != formatting_element)
while (current_node() != formatting_element)
(void)m_stack_of_open_elements.pop();
(void)m_stack_of_open_elements.pop();
@ -1943,7 +1947,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
close_a_p_element();
// If the current node is an HTML element whose tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then this is a parse error; pop the current node off the stack of open elements.
if (current_node().local_name().is_one_of(HTML::TagNames::h1, HTML::TagNames::h2, HTML::TagNames::h3, HTML::TagNames::h4, HTML::TagNames::h5, HTML::TagNames::h6)) {
if (current_node()->local_name().is_one_of(HTML::TagNames::h1, HTML::TagNames::h2, HTML::TagNames::h3, HTML::TagNames::h4, HTML::TagNames::h5, HTML::TagNames::h6)) {
log_parse_error();
(void)m_stack_of_open_elements.pop();
}
@ -2011,7 +2015,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
generate_implied_end_tags(HTML::TagNames::li);
// 2. If the current node is not an li element, then this is a parse error.
if (current_node().local_name() != HTML::TagNames::li) {
if (current_node()->local_name() != HTML::TagNames::li) {
log_parse_error();
}
@ -2052,7 +2056,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
if (node->local_name() == HTML::TagNames::dd) {
generate_implied_end_tags(HTML::TagNames::dd);
// 2. If the current node is not a dd element, then this is a parse error.
if (current_node().local_name() != HTML::TagNames::dd) {
if (current_node()->local_name() != HTML::TagNames::dd) {
log_parse_error();
}
@ -2067,7 +2071,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
if (node->local_name() == HTML::TagNames::dt) {
// 2. If the current node is not a dt element, then this is a parse error.
generate_implied_end_tags(HTML::TagNames::dt);
if (current_node().local_name() != HTML::TagNames::dt) {
if (current_node()->local_name() != HTML::TagNames::dt) {
log_parse_error();
}
// 3. Pop elements from the stack of open elements until a dt element has been popped from the stack.
@ -2145,7 +2149,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
generate_implied_end_tags();
// 2. If the current node is not an HTML element with the same tag name as that of the token, then this is a parse error.
if (current_node().local_name() != token.tag_name()) {
if (current_node()->local_name() != token.tag_name()) {
log_parse_error();
}
@ -2174,7 +2178,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
generate_implied_end_tags();
// 5. If the current node is not node, then this is a parse error.
if (&current_node() != node.ptr()) {
if (current_node() != node) {
log_parse_error();
}
@ -2193,7 +2197,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
generate_implied_end_tags();
// 3. If the current node is not a form element, then this is a parse error.
if (current_node().local_name() != HTML::TagNames::form) {
if (current_node()->local_name() != HTML::TagNames::form) {
log_parse_error();
}
@ -2229,9 +2233,9 @@ void HTMLParser::handle_in_body(HTMLToken& token)
generate_implied_end_tags(HTML::TagNames::li);
// 2. If the current node is not an li element, then this is a parse error.
if (current_node().local_name() != HTML::TagNames::li) {
if (current_node()->local_name() != HTML::TagNames::li) {
log_parse_error();
dbgln("Expected <li> current node, but had <{}>", current_node().local_name());
dbgln("Expected <li> current node, but had <{}>", current_node()->local_name());
}
// 3. Pop elements from the stack of open elements until an li element has been popped from the stack.
@ -2252,7 +2256,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
generate_implied_end_tags(token.tag_name());
// 2. If the current node is not an HTML element with the same tag name as that of the token, then this is a parse error.
if (current_node().local_name() != token.tag_name()) {
if (current_node()->local_name() != token.tag_name()) {
log_parse_error();
}
@ -2279,7 +2283,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
generate_implied_end_tags();
// 2. If the current node is not an HTML element with the same tag name as that of the token, then this is a parse error.
if (current_node().local_name() != token.tag_name()) {
if (current_node()->local_name() != token.tag_name()) {
log_parse_error();
}
@ -2382,7 +2386,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
generate_implied_end_tags();
// 2. If the current node is not an HTML element with the same tag name as that of the token, then this is a parse error.
if (current_node().local_name() != token.tag_name()) {
if (current_node()->local_name() != token.tag_name()) {
log_parse_error();
}
@ -2599,7 +2603,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
// -> A start tag whose tag name is one of: "optgroup", "option"
if (token.is_start_tag() && token.tag_name().is_one_of(HTML::TagNames::optgroup, HTML::TagNames::option)) {
// If the current node is an option element, then pop the current node off the stack of open elements.
if (current_node().local_name() == HTML::TagNames::option)
if (current_node()->local_name() == HTML::TagNames::option)
(void)m_stack_of_open_elements.pop();
// Reconstruct the active formatting elements, if any.
@ -2615,7 +2619,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
// If the stack of open elements has a ruby element in scope, then generate implied end tags. If the current node is not now a ruby element, this is a parse error.
if (m_stack_of_open_elements.has_in_scope(HTML::TagNames::ruby))
generate_implied_end_tags();
if (current_node().local_name() != HTML::TagNames::ruby)
if (current_node()->local_name() != HTML::TagNames::ruby)
log_parse_error();
// Insert an HTML element for the token.
@ -2628,7 +2632,7 @@ void HTMLParser::handle_in_body(HTMLToken& token)
// If the stack of open elements has a ruby element in scope, then generate implied end tags, except for rtc elements. If the current node is not now a rtc element or a ruby element, this is a parse error.
if (m_stack_of_open_elements.has_in_scope(HTML::TagNames::ruby))
generate_implied_end_tags(HTML::TagNames::rtc);
if (current_node().local_name() != HTML::TagNames::rtc || current_node().local_name() != HTML::TagNames::ruby)
if (current_node()->local_name() != HTML::TagNames::rtc || current_node()->local_name() != HTML::TagNames::ruby)
log_parse_error();
// Insert an HTML element for the token.
@ -2712,12 +2716,12 @@ void HTMLParser::handle_in_body(HTMLToken& token)
generate_implied_end_tags(token.tag_name());
// 2. If node is not the current node, then this is a parse error.
if (node.ptr() != &current_node()) {
if (node != current_node()) {
log_parse_error();
}
// 3. Pop all the nodes from the current node up to node, including node, then stop these steps.
while (&current_node() != node.ptr()) {
while (current_node() != node) {
(void)m_stack_of_open_elements.pop();
}
(void)m_stack_of_open_elements.pop();
@ -2916,8 +2920,8 @@ void HTMLParser::handle_text(HTMLToken& token)
}
if (token.is_end_of_file()) {
log_parse_error();
if (current_node().local_name() == HTML::TagNames::script)
verify_cast<HTMLScriptElement>(current_node()).set_already_started(Badge<HTMLParser> {}, true);
if (current_node()->local_name() == HTML::TagNames::script)
verify_cast<HTMLScriptElement>(*current_node()).set_already_started(Badge<HTMLParser> {}, true);
(void)m_stack_of_open_elements.pop();
m_insertion_mode = m_original_insertion_mode;
process_using_the_rules_for(m_insertion_mode, token);
@ -2938,7 +2942,7 @@ void HTMLParser::handle_text(HTMLToken& token)
perform_a_microtask_checkpoint();
// Let script be the current node (which will be a script element).
JS::NonnullGCPtr<HTMLScriptElement> script = verify_cast<HTMLScriptElement>(current_node());
JS::NonnullGCPtr<HTMLScriptElement> script = verify_cast<HTMLScriptElement>(*current_node());
// Pop the current node off the stack of open elements.
(void)m_stack_of_open_elements.pop();
@ -3050,28 +3054,28 @@ void HTMLParser::handle_text(HTMLToken& token)
void HTMLParser::clear_the_stack_back_to_a_table_context()
{
while (!current_node().local_name().is_one_of(HTML::TagNames::table, HTML::TagNames::template_, HTML::TagNames::html))
while (!current_node()->local_name().is_one_of(HTML::TagNames::table, HTML::TagNames::template_, HTML::TagNames::html))
(void)m_stack_of_open_elements.pop();
if (current_node().local_name() == HTML::TagNames::html)
if (current_node()->local_name() == HTML::TagNames::html)
VERIFY(m_parsing_fragment);
}
void HTMLParser::clear_the_stack_back_to_a_table_row_context()
{
while (!current_node().local_name().is_one_of(HTML::TagNames::tr, HTML::TagNames::template_, HTML::TagNames::html))
while (!current_node()->local_name().is_one_of(HTML::TagNames::tr, HTML::TagNames::template_, HTML::TagNames::html))
(void)m_stack_of_open_elements.pop();
if (current_node().local_name() == HTML::TagNames::html)
if (current_node()->local_name() == HTML::TagNames::html)
VERIFY(m_parsing_fragment);
}
void HTMLParser::clear_the_stack_back_to_a_table_body_context()
{
while (!current_node().local_name().is_one_of(HTML::TagNames::tbody, HTML::TagNames::tfoot, HTML::TagNames::thead, HTML::TagNames::template_, HTML::TagNames::html))
while (!current_node()->local_name().is_one_of(HTML::TagNames::tbody, HTML::TagNames::tfoot, HTML::TagNames::thead, HTML::TagNames::template_, HTML::TagNames::html))
(void)m_stack_of_open_elements.pop();
if (current_node().local_name() == HTML::TagNames::html)
if (current_node()->local_name() == HTML::TagNames::html)
VERIFY(m_parsing_fragment);
}
@ -3181,10 +3185,10 @@ void HTMLParser::handle_in_row(HTMLToken& token)
void HTMLParser::close_the_cell()
{
generate_implied_end_tags();
if (!current_node().local_name().is_one_of(HTML::TagNames::td, HTML::TagNames::th)) {
if (!current_node()->local_name().is_one_of(HTML::TagNames::td, HTML::TagNames::th)) {
log_parse_error();
}
while (!current_node().local_name().is_one_of(HTML::TagNames::td, HTML::TagNames::th))
while (!current_node()->local_name().is_one_of(HTML::TagNames::td, HTML::TagNames::th))
(void)m_stack_of_open_elements.pop();
(void)m_stack_of_open_elements.pop();
m_list_of_active_formatting_elements.clear_up_to_the_last_marker();
@ -3200,7 +3204,7 @@ void HTMLParser::handle_in_cell(HTMLToken& token)
}
generate_implied_end_tags();
if (current_node().local_name() != token.tag_name()) {
if (current_node()->local_name() != token.tag_name()) {
log_parse_error();
}
@ -3340,7 +3344,7 @@ void HTMLParser::handle_in_table_body(HTMLToken& token)
void HTMLParser::handle_in_table(HTMLToken& token)
{
// A character token, if the current node is table, tbody, template, tfoot, thead, or tr element
if (token.is_character() && current_node().local_name().is_one_of(HTML::TagNames::table, HTML::TagNames::tbody, HTML::TagNames::tfoot, HTML::TagNames::thead, HTML::TagNames::tr)) {
if (token.is_character() && current_node()->local_name().is_one_of(HTML::TagNames::table, HTML::TagNames::tbody, HTML::TagNames::tfoot, HTML::TagNames::thead, HTML::TagNames::tr)) {
// Let the pending table character tokens be an empty list of tokens.
m_pending_table_character_tokens.clear();
@ -3600,7 +3604,7 @@ void HTMLParser::handle_in_select(HTMLToken& token)
}
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::option) {
if (current_node().local_name() == HTML::TagNames::option) {
if (current_node()->local_name() == HTML::TagNames::option) {
(void)m_stack_of_open_elements.pop();
}
(void)insert_html_element(token);
@ -3608,10 +3612,10 @@ void HTMLParser::handle_in_select(HTMLToken& token)
}
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::optgroup) {
if (current_node().local_name() == HTML::TagNames::option) {
if (current_node()->local_name() == HTML::TagNames::option) {
(void)m_stack_of_open_elements.pop();
}
if (current_node().local_name() == HTML::TagNames::optgroup) {
if (current_node()->local_name() == HTML::TagNames::optgroup) {
(void)m_stack_of_open_elements.pop();
}
(void)insert_html_element(token);
@ -3621,11 +3625,11 @@ void HTMLParser::handle_in_select(HTMLToken& token)
// -> A start tag whose tag name is "hr"
if (token.is_start_tag() && token.tag_name() == HTML::TagNames::hr) {
// If the current node is an option element, pop that node from the stack of open elements.
if (current_node().local_name() == HTML::TagNames::option) {
if (current_node()->local_name() == HTML::TagNames::option) {
(void)m_stack_of_open_elements.pop();
}
// If the current node is an optgroup element, pop that node from the stack of open elements.
if (current_node().local_name() == HTML::TagNames::optgroup) {
if (current_node()->local_name() == HTML::TagNames::optgroup) {
(void)m_stack_of_open_elements.pop();
}
// Insert an HTML element for the token. Immediately pop the current node off the stack of open elements.
@ -3637,10 +3641,10 @@ void HTMLParser::handle_in_select(HTMLToken& token)
}
if (token.is_end_tag() && token.tag_name() == HTML::TagNames::optgroup) {
if (current_node().local_name() == HTML::TagNames::option && node_before_current_node().local_name() == HTML::TagNames::optgroup)
if (current_node()->local_name() == HTML::TagNames::option && node_before_current_node()->local_name() == HTML::TagNames::optgroup)
(void)m_stack_of_open_elements.pop();
if (current_node().local_name() == HTML::TagNames::optgroup) {
if (current_node()->local_name() == HTML::TagNames::optgroup) {
(void)m_stack_of_open_elements.pop();
} else {
log_parse_error();
@ -3650,7 +3654,7 @@ void HTMLParser::handle_in_select(HTMLToken& token)
}
if (token.is_end_tag() && token.tag_name() == HTML::TagNames::option) {
if (current_node().local_name() == HTML::TagNames::option) {
if (current_node()->local_name() == HTML::TagNames::option) {
(void)m_stack_of_open_elements.pop();
} else {
log_parse_error();
@ -3726,7 +3730,7 @@ void HTMLParser::handle_in_caption(HTMLToken& token)
generate_implied_end_tags();
if (current_node().local_name() != HTML::TagNames::caption)
if (current_node()->local_name() != HTML::TagNames::caption)
log_parse_error();
m_stack_of_open_elements.pop_until_an_element_with_tag_name_has_been_popped(HTML::TagNames::caption);
@ -3746,7 +3750,7 @@ void HTMLParser::handle_in_caption(HTMLToken& token)
generate_implied_end_tags();
if (current_node().local_name() != HTML::TagNames::caption)
if (current_node()->local_name() != HTML::TagNames::caption)
log_parse_error();
m_stack_of_open_elements.pop_until_an_element_with_tag_name_has_been_popped(HTML::TagNames::caption);
@ -3795,7 +3799,7 @@ void HTMLParser::handle_in_column_group(HTMLToken& token)
}
if (token.is_end_tag() && token.tag_name() == HTML::TagNames::colgroup) {
if (current_node().local_name() != HTML::TagNames::colgroup) {
if (current_node()->local_name() != HTML::TagNames::colgroup) {
log_parse_error();
return;
}
@ -3820,7 +3824,7 @@ void HTMLParser::handle_in_column_group(HTMLToken& token)
return;
}
if (current_node().local_name() != HTML::TagNames::colgroup) {
if (current_node()->local_name() != HTML::TagNames::colgroup) {
log_parse_error();
return;
}
@ -3950,7 +3954,7 @@ void HTMLParser::handle_in_frameset(HTMLToken& token)
// -> An end tag whose tag name is "frameset"
if (token.is_end_tag() && token.tag_name() == HTML::TagNames::frameset) {
// If the current node is the root html element, then this is a parse error; ignore the token. (fragment case)
if (current_node().is_document_element()) {
if (current_node()->is_document_element()) {
log_parse_error();
return;
}
@ -3960,7 +3964,7 @@ void HTMLParser::handle_in_frameset(HTMLToken& token)
// If the parser was not created as part of the HTML fragment parsing algorithm (fragment case),
// and the current node is no longer a frameset element, then switch the insertion mode to "after frameset".
if (!m_parsing_fragment && current_node().local_name() != HTML::TagNames::frameset) {
if (!m_parsing_fragment && current_node()->local_name() != HTML::TagNames::frameset) {
m_insertion_mode = InsertionMode::AfterFrameset;
}
return;
@ -3989,7 +3993,7 @@ void HTMLParser::handle_in_frameset(HTMLToken& token)
// -> An end-of-file token
if (token.is_end_of_file()) {
// If the current node is not the root html element, then this is a parse error.
if (!current_node().is_document_element()) {
if (!current_node()->is_document_element()) {
log_parse_error();
}
@ -4118,9 +4122,9 @@ void HTMLParser::process_using_the_rules_for_foreign_content(HTMLToken& token)
log_parse_error();
// While the current node is not a MathML text integration point, an HTML integration point, or an element in the HTML namespace, pop elements from the stack of open elements.
while (!is_mathml_text_integration_point(current_node())
&& !is_html_integration_point(current_node())
&& current_node().namespace_uri() != Namespace::HTML) {
while (!is_mathml_text_integration_point(*current_node())
&& !is_html_integration_point(*current_node())
&& current_node()->namespace_uri() != Namespace::HTML) {
(void)m_stack_of_open_elements.pop();
}
@ -4132,13 +4136,13 @@ void HTMLParser::process_using_the_rules_for_foreign_content(HTMLToken& token)
// Any other start tag
if (token.is_start_tag()) {
// If the adjusted current node is an element in the MathML namespace, adjust MathML attributes for the token. (This fixes the case of MathML attributes that are not all lowercase.)
if (adjusted_current_node().namespace_uri() == Namespace::MathML) {
if (adjusted_current_node()->namespace_uri() == Namespace::MathML) {
adjust_mathml_attributes(token);
}
// If the adjusted current node is an element in the SVG namespace, and the token's tag name is one of the ones in the first column of the
// following table, change the tag name to the name given in the corresponding cell in the second column. (This fixes the case of SVG
// elements that are not all lowercase.)
else if (adjusted_current_node().namespace_uri() == Namespace::SVG) {
else if (adjusted_current_node()->namespace_uri() == Namespace::SVG) {
adjust_svg_tag_names(token);
// If the adjusted current node is an element in the SVG namespace, adjust SVG attributes for the token. (This fixes the case of SVG attributes that are not all lowercase.)
adjust_svg_attributes(token);
@ -4148,14 +4152,14 @@ void HTMLParser::process_using_the_rules_for_foreign_content(HTMLToken& token)
adjust_foreign_attributes(token);
// Insert a foreign element for the token, with adjusted current node's namespace and false.
(void)insert_foreign_element(token, adjusted_current_node().namespace_uri(), OnlyAddToElementStack::No);
(void)insert_foreign_element(token, adjusted_current_node()->namespace_uri(), OnlyAddToElementStack::No);
// If the token has its self-closing flag set, then run the appropriate steps from the following list:
if (token.is_self_closing()) {
// -> If the token's tag name is "script", and the new current node is in the SVG namespace
if (token.tag_name() == SVG::TagNames::script && current_node().namespace_uri() == Namespace::SVG) {
auto& script_element = verify_cast<SVG::SVGScriptElement>(current_node());
if (token.tag_name() == SVG::TagNames::script && current_node()->namespace_uri() == Namespace::SVG) {
auto& script_element = verify_cast<SVG::SVGScriptElement>(*current_node());
script_element.set_source_line_number({}, token.start_position().line + 1); // FIXME: This +1 is incorrect for script tags whose script does not start on a new line
// Acknowledge the token's self-closing flag, and then act as described in the steps for a "script" end tag below.
@ -4174,7 +4178,7 @@ void HTMLParser::process_using_the_rules_for_foreign_content(HTMLToken& token)
}
// -> An end tag whose tag name is "script", if the current node is an SVG script element
if (token.is_end_tag() && current_node().namespace_uri() == Namespace::SVG && current_node().tag_name() == SVG::TagNames::script) {
if (token.is_end_tag() && current_node()->namespace_uri() == Namespace::SVG && current_node()->tag_name() == SVG::TagNames::script) {
ScriptEndTag:
// Pop the current node off the stack of open elements.
auto& script_element = verify_cast<SVG::SVGScriptElement>(*m_stack_of_open_elements.pop());
@ -4224,7 +4228,7 @@ void HTMLParser::process_using_the_rules_for_foreign_content(HTMLToken& token)
// 4. If node's tag name, converted to ASCII lowercase, is the same as the tag name of the token, pop elements from the stack
// of open elements until node has been popped from the stack, and then return.
if (node->tag_name().equals_ignoring_ascii_case(token.tag_name())) {
while (&current_node() != node.ptr())
while (current_node() != node)
(void)m_stack_of_open_elements.pop();
(void)m_stack_of_open_elements.pop();
return;

View file

@ -148,9 +148,9 @@ private:
};
JS::NonnullGCPtr<DOM::Element> insert_foreign_element(HTMLToken const&, Optional<FlyString> const& namespace_, OnlyAddToElementStack);
JS::NonnullGCPtr<DOM::Element> insert_html_element(HTMLToken const&);
DOM::Element& current_node();
DOM::Element& adjusted_current_node();
DOM::Element& node_before_current_node();
[[nodiscard]] JS::GCPtr<DOM::Element> current_node();
[[nodiscard]] JS::GCPtr<DOM::Element> adjusted_current_node();
[[nodiscard]] JS::GCPtr<DOM::Element> node_before_current_node();
void insert_character(u32 data);
void insert_comment(HTMLToken&);
void reconstruct_the_active_formatting_elements();

View file

@ -433,7 +433,9 @@ _StartOfFunction:
if (consume_next_if_match("[CDATA["sv)) {
// We keep the parser optional so that syntax highlighting can be lexer-only.
// The parser registers itself with the lexer it creates.
if (m_parser != nullptr && m_parser->adjusted_current_node().namespace_uri() != Namespace::HTML) {
if (m_parser != nullptr
&& m_parser->adjusted_current_node()
&& m_parser->adjusted_current_node()->namespace_uri() != Namespace::HTML) {
SWITCH_TO(CDATASection);
} else {
create_new_token(HTMLToken::Type::Comment);