LibWeb: Execute the correct script in XMLDocumentBuilder::element_end()

We were mistakenly executing the current node's script instead of the
document's pending parsing-blocking script.

This caused ~1000 WPT tests to time out, since we never ended up firing
a load event for XHTML pages that load multiple external scripts.
This commit is contained in:
Andreas Kling 2024-07-25 14:08:45 +02:00 committed by Andreas Kling
parent b011d47b86
commit 007c292af3
Notes: github-actions[bot] 2024-07-25 13:06:19 +00:00
7 changed files with 26 additions and 13 deletions

View file

@ -0,0 +1 @@
PASS

View file

@ -0,0 +1,10 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<script src="../include.js"></script>
<script>
test(() => {
println("PASS");
});
</script>
</body>
</html>

View file

@ -1724,7 +1724,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<Event>> Document::create_event(StringView i
return JS::NonnullGCPtr(*event);
}
void Document::set_pending_parsing_blocking_script(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement* script)
void Document::set_pending_parsing_blocking_script(HTML::HTMLScriptElement* script)
{
m_pending_parsing_blocking_script = script;
}

View file

@ -286,7 +286,7 @@ public:
WebIDL::ExceptionOr<JS::NonnullGCPtr<Event>> create_event(StringView interface);
JS::NonnullGCPtr<Range> create_range();
void set_pending_parsing_blocking_script(Badge<HTML::HTMLScriptElement>, HTML::HTMLScriptElement*);
void set_pending_parsing_blocking_script(HTML::HTMLScriptElement*);
HTML::HTMLScriptElement* pending_parsing_blocking_script() { return m_pending_parsing_blocking_script.ptr(); }
JS::NonnullGCPtr<HTML::HTMLScriptElement> take_pending_parsing_blocking_script(Badge<HTML::HTMLParser>);

View file

@ -536,7 +536,7 @@ void HTMLScriptElement::prepare_script()
// 5. Otherwise:
else {
// 1. Set el's parser document's pending parsing-blocking script to el.
m_parser_document->set_pending_parsing_blocking_script({}, this);
m_parser_document->set_pending_parsing_blocking_script(this);
// FIXME: 2. Block rendering on el.
@ -563,7 +563,7 @@ void HTMLScriptElement::prepare_script()
&& is_parser_inserted()
&& m_parser_document->has_a_style_sheet_that_is_blocking_scripts()) {
// 1. Set el's parser document's pending parsing-blocking script to el.
m_parser_document->set_pending_parsing_blocking_script({}, this);
m_parser_document->set_pending_parsing_blocking_script(this);
// 2. Set el's ready to be parser-executed to true. (The parser will handle executing the script.)
m_ready_to_be_parser_executed = true;

View file

@ -117,25 +117,27 @@ void XMLDocumentBuilder::element_end(const XML::Name& name)
// and then prepare the script element.
auto& script_element = static_cast<HTML::HTMLScriptElement&>(*m_current_node);
script_element.prepare_script(Badge<XMLDocumentBuilder> {});
// If this causes there to be a pending parsing-blocking script, then the user agent must run the following steps:
if (m_document->pending_parsing_blocking_script()) {
// Block this instance of the XML parser, such that the event loop will not run tasks that invoke it.
if (auto pending_parsing_blocking_script = m_document->pending_parsing_blocking_script()) {
// 1. Block this instance of the XML parser, such that the event loop will not run tasks that invoke it.
// NOTE: Noop.
// Spin the event loop until the parser's Document has no style sheet that is blocking scripts and the pending parsing-blocking script's "ready to be parser-executed" flag is set.
if (m_document->has_a_style_sheet_that_is_blocking_scripts() || !script_element.is_ready_to_be_parser_executed()) {
// 2. Spin the event loop until the parser's Document has no style sheet that is blocking scripts and the pending parsing-blocking script's "ready to be parser-executed" flag is set.
if (m_document->has_a_style_sheet_that_is_blocking_scripts() || !pending_parsing_blocking_script->is_ready_to_be_parser_executed()) {
HTML::main_thread_event_loop().spin_until([&] {
return !m_document->has_a_style_sheet_that_is_blocking_scripts() && script_element.is_ready_to_be_parser_executed();
return !m_document->has_a_style_sheet_that_is_blocking_scripts() && pending_parsing_blocking_script->is_ready_to_be_parser_executed();
});
}
// Unblock this instance of the XML parser, such that tasks that invoke it can again be run.
// 3. Unblock this instance of the XML parser, such that tasks that invoke it can again be run.
// NOTE: Noop.
// Execute the pending parsing-blocking script.
script_element.execute_script();
// 4. Execute the script element given by the pending parsing-blocking script.
pending_parsing_blocking_script->execute_script();
// There is no longer a pending parsing-blocking script.
// 5. Set the pending parsing-blocking script to null.
m_document->set_pending_parsing_blocking_script(nullptr);
}
} else if (m_scripting_support == XMLScriptingSupport::Enabled && m_current_node->is_svg_script_element()) {
// https://www.w3.org/TR/SVGMobile12/struct.html#ProgressiveRendering