This commit is contained in:
Andreas Kling 2025-04-20 12:49:42 +02:00 committed by GitHub
commit 86f2ee2efa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 101 additions and 18 deletions

View file

@ -583,6 +583,7 @@ void Document::visit_edges(Cell::Visitor& visitor)
}
visitor.visit(m_adopted_style_sheets);
visitor.visit(m_script_blocking_style_sheet_set);
for (auto& shadow_root : m_shadow_roots)
visitor.visit(shadow_root);
@ -3242,11 +3243,18 @@ String Document::dump_dom_tree_as_json() const
return MUST(builder.to_string());
}
// https://html.spec.whatwg.org/multipage/semantics.html#has-no-style-sheet-that-is-blocking-scripts
bool Document::has_no_style_sheet_that_is_blocking_scripts() const
{
// A Document has no style sheet that is blocking scripts if it does not have a style sheet that is blocking scripts.
return !has_a_style_sheet_that_is_blocking_scripts();
}
// https://html.spec.whatwg.org/multipage/semantics.html#has-a-style-sheet-that-is-blocking-scripts
bool Document::has_a_style_sheet_that_is_blocking_scripts() const
{
// FIXME: 1. If document's script-blocking style sheet set is not empty, then return true.
if (m_script_blocking_style_sheet_counter > 0)
// 1. If document's script-blocking style sheet set is not empty, then return true.
if (!m_script_blocking_style_sheet_set.is_empty())
return true;
// 2. If document's node navigable is null, then return false.
@ -3256,8 +3264,8 @@ bool Document::has_a_style_sheet_that_is_blocking_scripts() const
// 3. Let containerDocument be document's node navigable's container document.
auto container_document = navigable()->container_document();
// FIXME: 4. If containerDocument is non-null and containerDocument's script-blocking style sheet set is not empty, then return true.
if (container_document && container_document->m_script_blocking_style_sheet_counter > 0)
// 4. If containerDocument is non-null and containerDocument's script-blocking style sheet set is not empty, then return true.
if (container_document && !container_document->m_script_blocking_style_sheet_set.is_empty())
return true;
// 5. Return false

View file

@ -499,7 +499,8 @@ public:
String dump_dom_tree_as_json() const;
bool has_a_style_sheet_that_is_blocking_scripts() const;
[[nodiscard]] bool has_a_style_sheet_that_is_blocking_scripts() const;
[[nodiscard]] bool has_no_style_sheet_that_is_blocking_scripts() const;
bool is_fully_active() const;
bool is_active() const;
@ -897,6 +898,9 @@ public:
ElementByIdMap& element_by_id() const;
auto& script_blocking_style_sheet_set() { return m_script_blocking_style_sheet_set; }
auto const& script_blocking_style_sheet_set() const { return m_script_blocking_style_sheet_set; }
protected:
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(Cell::Visitor&) override;
@ -1030,8 +1034,8 @@ private:
// https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#throw-on-dynamic-markup-insertion-counter
u32 m_throw_on_dynamic_markup_insertion_counter { 0 };
// https://html.spec.whatwg.org/multipage/semantics.html#script-blocking-style-sheet-counter
u32 m_script_blocking_style_sheet_counter { 0 };
// https://html.spec.whatwg.org/multipage/semantics.html#script-blocking-style-sheet-set
HashTable<GC::Ref<DOM::Element>> m_script_blocking_style_sheet_set;
GC::Ptr<HTML::History> m_history;

View file

@ -471,6 +471,8 @@ public:
void release_pointer_capture(WebIDL::Long pointer_id);
bool has_pointer_capture(WebIDL::Long pointer_id);
virtual bool contributes_a_script_blocking_style_sheet() const { return false; }
protected:
Element(Document&, DOM::QualifiedName);
virtual void initialize(JS::Realm&) override;

View file

@ -87,6 +87,12 @@ void StyleElementUtils::update_a_style_block(DOM::Element& style_element)
{},
nullptr,
nullptr);
// 7. If element contributes a script-blocking style sheet, append element to its node document's script-blocking style sheet set.
if (style_element.contributes_a_script_blocking_style_sheet())
style_element.document().script_blocking_style_sheet_set().set(style_element);
// FIXME: 8. If element's media attribute's value matches the environment and element is potentially render-blocking, then block rendering on element.
}
void StyleElementUtils::visit_edges(JS::Cell::Visitor& visitor)

View file

@ -509,9 +509,14 @@ void HTMLLinkElement::process_stylesheet_resource(bool success, Fetch::Infrastru
dispatch_event(*DOM::Event::create(realm(), HTML::EventNames::error));
}
// FIXME: 6. If el contributes a script-blocking style sheet, then:
// FIXME: 1. Assert: el's node document's script-blocking style sheet counter is greater than 0.
// FIXME: 2. Decrement el's node document's script-blocking style sheet counter by 1.
// 6. If el contributes a script-blocking style sheet, then:
if (contributes_a_script_blocking_style_sheet()) {
// 1. Assert: el's node document's script-blocking style sheet set contains el.
VERIFY(document().script_blocking_style_sheet_set().contains(*this));
// 2. Remove el from its node document's script-blocking style sheet set.
document().script_blocking_style_sheet_set().remove(*this);
}
// 7. Unblock rendering on el.
unblock_rendering();
@ -541,7 +546,10 @@ bool HTMLLinkElement::stylesheet_linked_resource_fetch_setup_steps(Fetch::Infras
// 1. If el's disabled attribute is set, then return false.
if (has_attribute(AttributeNames::disabled))
return false;
// FIXME: 2. If el contributes a script-blocking style sheet, increment el's node document's script-blocking style sheet counter by 1.
// 2. If el contributes a script-blocking style sheet, append el to its node document's script-blocking style sheet set.
if (contributes_a_script_blocking_style_sheet())
document().script_blocking_style_sheet_set().set(*this);
// 3. If el's media attribute's value matches the environment and el is potentially render-blocking, then block rendering on el.
// FIXME: Check media attribute value.
@ -674,4 +682,34 @@ void HTMLLinkElement::visit_edges(Cell::Visitor& visitor)
visitor.visit(m_sizes);
}
// https://html.spec.whatwg.org/multipage/semantics.html#contributes-a-script-blocking-style-sheet
bool HTMLLinkElement::contributes_a_script_blocking_style_sheet() const
{
// An element el in the context of a Document of an HTML parser or XML parser
// contributes a script-blocking style sheet if all of the following are true:
// el was created by that Document's parser.
if (m_parser_document != &document())
return false;
// FIXME: el is either a style element or a link element that was an external resource link that contributes to the styling processing model when the el was created by the parser.
// FIXME: el's media attribute's value matches the environment.
// FIXME: el's style sheet was enabled when the element was created by the parser.
if (has_attribute(AttributeNames::disabled))
return false;
// FIXME: The last time the event loop reached step 1, el's root was that Document.
// The user agent hasn't given up on loading that particular style sheet yet.
// A user agent may give up on loading a style sheet at any time.
if (m_fetch_controller && m_fetch_controller->state() == Fetch::Infrastructure::FetchController::State::Terminated)
return false;
if (m_fetch_controller && m_fetch_controller->state() == Fetch::Infrastructure::FetchController::State::Aborted)
return false;
return true;
}
}

View file

@ -50,6 +50,8 @@ public:
GC::Ptr<CSS::CSSStyleSheet> sheet() const;
virtual bool contributes_a_script_blocking_style_sheet() const final;
private:
HTMLLinkElement(DOM::Document&, DOM::QualifiedName);

View file

@ -103,4 +103,27 @@ CSS::CSSStyleSheet const* HTMLStyleElement::sheet() const
return m_style_element_utils.sheet();
}
// https://html.spec.whatwg.org/multipage/semantics.html#contributes-a-script-blocking-style-sheet
bool HTMLStyleElement::contributes_a_script_blocking_style_sheet() const
{
// An element el in the context of a Document of an HTML parser or XML parser
// contributes a script-blocking style sheet if all of the following are true:
// FIXME: el was created by that Document's parser.
// el is either a style element or a link element that was an external resource link that contributes to the styling processing model when the el was created by the parser.
// NOTE: This is a style element, so all good!
// FIXME: el's media attribute's value matches the environment.
// FIXME: el's style sheet was enabled when the element was created by the parser.
// FIXME: The last time the event loop reached step 1, el's root was that Document.
// FIXME: The user agent hasn't given up on loading that particular style sheet yet.
// A user agent may give up on loading a style sheet at any time.
return false;
}
}

View file

@ -30,6 +30,8 @@ public:
CSS::CSSStyleSheet* sheet();
CSS::CSSStyleSheet const* sheet() const;
virtual bool contributes_a_script_blocking_style_sheet() const final;
private:
HTMLStyleElement(DOM::Document&, DOM::QualifiedName);

View file

@ -1,13 +1,11 @@
<!DOCTYPE html>
<script src="include.js"></script>
<link rel="stylesheet" href="valid.css">
<script>
var scriptOnloadWasInvoked = false;
</script>
<link id="link" rel="stylesheet" href="valid.css" onload="link.disabled = true; link.disabled = false;">
<script>
test(() => {
const link = document.querySelector("link");
link.onload = () => {
link.disabled = true;
link.disabled = false;
println("PASS (didn't crash)");
};
println("PASS (didn't crash)");
});
</script>