LibWeb: Move style element hooks to StyleElementBase

Move HTMLStyleElement's dynamic update handling, media/type attribute
handling, and script-blocking predicate skeleton into StyleElementBase
so style elements can share that plumbing.
This commit is contained in:
Sam Atkins 2026-06-03 14:55:54 +01:00
parent 5cc0e1408a
commit c1953f93c7
5 changed files with 52 additions and 30 deletions

View file

@ -14,11 +14,27 @@
#include <LibWeb/DOM/Event.h>
#include <LibWeb/DOM/ShadowRoot.h>
#include <LibWeb/DOM/StyleElementBase.h>
#include <LibWeb/HTML/AttributeNames.h>
#include <LibWeb/HTML/EventNames.h>
#include <LibWeb/Infra/Strings.h>
namespace Web::DOM {
void StyleElementBase::update_a_style_block_for_dynamic_change()
{
update_a_style_block();
}
void StyleElementBase::style_element_attribute_changed(FlyString const& name, Optional<String> const& value)
{
if (name == HTML::AttributeNames::media) {
if (auto* sheet = this->sheet())
sheet->set_media(value.value_or({}));
} else if (name == HTML::AttributeNames::type) {
update_a_style_block_for_dynamic_change();
}
}
// The user agent must run the "update a style block" algorithm whenever one of the following conditions occur:
// FIXME: The element is popped off the stack of open elements of an HTML parser or XML parser.
//
@ -152,6 +168,29 @@ void StyleElementBase::finished_loading_critical_subresources(AnyFailed any_fail
m_document_load_event_delayer.clear();
}
// https://html.spec.whatwg.org/multipage/semantics.html#contributes-a-script-blocking-style-sheet
bool StyleElementBase::style_element_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;
}
// https://www.w3.org/TR/cssom/#dom-linkstyle-sheet
CSS::CSSStyleSheet* StyleElementBase::sheet()
{

View file

@ -18,6 +18,8 @@ public:
virtual ~StyleElementBase() = default;
void update_a_style_block();
void update_a_style_block_for_dynamic_change();
void style_element_attribute_changed(FlyString const&, Optional<String> const& value);
CSS::CSSStyleSheet* sheet();
CSS::CSSStyleSheet const* sheet() const;
@ -34,6 +36,10 @@ public:
void visit_style_element_edges(JS::Cell::Visitor&);
virtual Element& as_element() = 0;
virtual Element const& as_element() const = 0;
protected:
bool style_element_contributes_a_script_blocking_style_sheet() const;
private:
// https://www.w3.org/TR/cssom/#associated-css-style-sheet

View file

@ -7,8 +7,6 @@
*/
#include <LibWeb/Bindings/HTMLStyleElement.h>
#include <LibWeb/CSS/StyleComputer.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/HTML/HTMLStyleElement.h>
namespace Web::HTML {
@ -37,31 +35,25 @@ void HTMLStyleElement::visit_edges(Cell::Visitor& visitor)
void HTMLStyleElement::children_changed(ChildrenChangedMetadata const& metadata)
{
Base::children_changed(metadata);
update_a_style_block();
update_a_style_block_for_dynamic_change();
}
void HTMLStyleElement::inserted()
{
Base::inserted();
update_a_style_block();
update_a_style_block_for_dynamic_change();
}
void HTMLStyleElement::removed_from(IsSubtreeRoot is_subtree_root, Node* old_ancestor, Node& old_root)
{
Base::removed_from(is_subtree_root, old_ancestor, old_root);
update_a_style_block();
update_a_style_block_for_dynamic_change();
}
void HTMLStyleElement::attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_)
{
Base::attribute_changed(name, old_value, value, namespace_);
if (name == HTML::AttributeNames::media) {
if (auto* sheet = this->sheet())
sheet->set_media(value.value_or({}));
} else if (name == HTML::AttributeNames::type) {
update_a_style_block();
}
style_element_attribute_changed(name, value);
}
// https://html.spec.whatwg.org/multipage/semantics.html#dom-style-disabled
@ -94,24 +86,7 @@ void HTMLStyleElement::set_disabled(bool disabled)
// 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;
return style_element_contributes_a_script_blocking_style_sheet();
}
}

View file

@ -39,6 +39,7 @@ private:
// ^DOM::StyleElementBase
virtual Element& as_element() override { return *this; }
virtual Element const& as_element() const override { return *this; }
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(Cell::Visitor&) override;

View file

@ -32,6 +32,7 @@ private:
// ^DOM::StyleElementBase
virtual Element& as_element() override { return *this; }
virtual Element const& as_element() const override { return *this; }
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(Cell::Visitor&) override;