LibWeb: Add metadata to children update steps invocation

Currently, this metadata is only provided on the insertion steps,
though I believe it would be useful to extend to the other cases
as well. This metadata can aid in making optimizations for these
steps by providing extra context into the type of change which
was made on the child.
This commit is contained in:
Shannon Booth 2025-01-27 01:16:33 +13:00 committed by Andrew Kaster
commit 903c8860f8
Notes: github-actions[bot] 2025-01-30 20:56:50 +00:00
27 changed files with 52 additions and 40 deletions

View file

@ -126,7 +126,7 @@ WebIDL::ExceptionOr<void> CharacterData::replace_data(size_t offset, size_t coun
// 12. If nodes parent is non-null, then run the children changed steps for nodes parent.
if (parent())
parent()->children_changed();
parent()->children_changed(nullptr);
// NOTE: Since the text node's data has changed, we need to invalidate the text for rendering.
// This ensures that the new text is reflected in layout, even if we don't end up

View file

@ -1107,9 +1107,9 @@ void Element::removed_from(Node* old_parent, Node& old_root)
document().element_with_name_was_removed({}, *this);
}
void Element::children_changed()
void Element::children_changed(ChildrenChangedMetadata const* metadata)
{
Node::children_changed();
Node::children_changed(metadata);
set_needs_style_update(true);
}

View file

@ -420,7 +420,7 @@ protected:
virtual void inserted() override;
virtual void removed_from(Node* old_parent, Node& old_root) override;
virtual void children_changed() override;
virtual void children_changed(ChildrenChangedMetadata const*) override;
virtual i32 default_tab_index_value() const;
// https://dom.spec.whatwg.org/#concept-element-attributes-change-ext

View file

@ -745,7 +745,8 @@ void Node::insert_before(GC::Ref<Node> node, GC::Ptr<Node> child, bool suppress_
}
// 9. Run the children changed steps for parent.
children_changed();
ChildrenChangedMetadata metadata { ChildrenChangedMetadata::Type::Inserted, node };
children_changed(&metadata);
// 10. Let staticNodeList be a list of nodes, initially « ».
// Spec-Note: We collect all nodes before calling the post-connection steps on any one of them, instead of calling
@ -977,7 +978,7 @@ void Node::remove(bool suppress_observers)
}
// 21. Run the children changed steps for parent.
parent->children_changed();
parent->children_changed(nullptr);
document().bump_dom_tree_version();
}

View file

@ -262,7 +262,18 @@ public:
virtual void inserted();
virtual void post_connection();
virtual void removed_from(Node* old_parent, Node& old_root);
virtual void children_changed() { }
struct ChildrenChangedMetadata {
enum class Type {
Inserted,
Removal,
Mutation,
};
Type type {};
GC::Ref<Node> node;
};
// FIXME: It would be good if we could always provide this metadata for use in optimizations.
virtual void children_changed(ChildrenChangedMetadata const*) { }
virtual void adopted_from(Document&) { }
virtual WebIDL::ExceptionOr<void> cloned(Node&, bool) const { return {}; }

View file

@ -100,9 +100,9 @@ void HTMLDetailsElement::attribute_changed(FlyString const& local_name, Optional
}
}
void HTMLDetailsElement::children_changed()
void HTMLDetailsElement::children_changed(ChildrenChangedMetadata const* metadata)
{
Base::children_changed();
Base::children_changed(metadata);
update_shadow_tree_slots();
}

View file

@ -33,7 +33,7 @@ private:
virtual void inserted() override;
virtual void removed_from(DOM::Node* old_parent, DOM::Node& old_root) override;
virtual void children_changed() override;
virtual void children_changed(ChildrenChangedMetadata const*) override;
virtual void attribute_changed(FlyString const& local_name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override;
void queue_a_details_toggle_event_task(String old_state, String new_state);

View file

@ -766,9 +766,9 @@ private:
GC_DEFINE_ALLOCATOR(SourceElementSelector);
void HTMLMediaElement::children_changed()
void HTMLMediaElement::children_changed(ChildrenChangedMetadata const* metadata)
{
Base::children_changed();
Base::children_changed(metadata);
if (m_source_element_selector)
m_source_element_selector->process_next_candidate().release_value_but_fixme_should_propagate_errors();

View file

@ -158,7 +158,7 @@ protected:
virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override;
virtual void removed_from(DOM::Node* old_parent, DOM::Node& old_root) override;
virtual void children_changed() override;
virtual void children_changed(ChildrenChangedMetadata const* metadata) override;
// Override in subclasses to handle implementation-specific behavior when the element state changes
// to playing or paused, e.g. to start/stop play timers.

View file

@ -253,9 +253,9 @@ void HTMLOptionElement::removed_from(Node* old_parent, Node& old_root)
}
}
void HTMLOptionElement::children_changed()
void HTMLOptionElement::children_changed(ChildrenChangedMetadata const* metadata)
{
Base::children_changed();
Base::children_changed(metadata);
update_selection_label();
}

View file

@ -55,7 +55,7 @@ private:
virtual void inserted() override;
virtual void removed_from(Node* old_parent, Node& old_root) override;
virtual void children_changed() override;
virtual void children_changed(ChildrenChangedMetadata const*) override;
void ask_for_a_reset();
void update_selection_label();

View file

@ -572,9 +572,9 @@ void HTMLScriptElement::prepare_script()
}
// https://html.spec.whatwg.org/multipage/scripting.html#script-processing-model:html-element-post-connection-steps-4
void HTMLScriptElement::children_changed()
void HTMLScriptElement::children_changed(ChildrenChangedMetadata const* metadata)
{
Base::children_changed();
Base::children_changed(metadata);
// 1. Run the script HTML element post-connection steps, given the script element.
post_connection();

View file

@ -43,7 +43,7 @@ public:
bool is_parser_inserted() const { return !!m_parser_document; }
virtual void children_changed() override;
virtual void children_changed(ChildrenChangedMetadata const*) override;
virtual void post_connection() override;
// https://html.spec.whatwg.org/multipage/scripting.html#dom-script-supports

View file

@ -292,9 +292,9 @@ i32 HTMLSelectElement::default_tab_index_value() const
return 0;
}
void HTMLSelectElement::children_changed()
void HTMLSelectElement::children_changed(ChildrenChangedMetadata const* metadata)
{
Base::children_changed();
Base::children_changed(metadata);
update_cached_list_of_options();
update_selectedness();
}

View file

@ -109,7 +109,7 @@ private:
virtual void computed_properties_changed() override;
virtual void children_changed() override;
virtual void children_changed(ChildrenChangedMetadata const*) override;
void update_cached_list_of_options() const;
void show_the_picker_if_applicable();

View file

@ -32,9 +32,9 @@ void HTMLStyleElement::visit_edges(Cell::Visitor& visitor)
m_style_element_utils.visit_edges(visitor);
}
void HTMLStyleElement::children_changed()
void HTMLStyleElement::children_changed(ChildrenChangedMetadata const* metadata)
{
Base::children_changed();
Base::children_changed(metadata);
m_style_element_utils.update_a_style_block(*this);
}

View file

@ -19,7 +19,7 @@ class HTMLStyleElement final : public HTMLElement {
public:
virtual ~HTMLStyleElement() override;
virtual void children_changed() override;
virtual void children_changed(ChildrenChangedMetadata const*) override;
virtual void inserted() override;
virtual void removed_from(Node* old_parent, Node& old_root) override;

View file

@ -429,9 +429,9 @@ void HTMLTextAreaElement::update_placeholder_visibility()
}
// https://html.spec.whatwg.org/multipage/form-elements.html#the-textarea-element:children-changed-steps
void HTMLTextAreaElement::children_changed()
void HTMLTextAreaElement::children_changed(ChildrenChangedMetadata const* metadata)
{
Base::children_changed();
Base::children_changed(metadata);
// The children changed steps for textarea elements must, if the element's dirty value flag is false,
// set the element's raw value to its child text content.

View file

@ -70,7 +70,7 @@ public:
virtual void form_associated_element_was_removed(DOM::Node*) override;
virtual void form_associated_element_attribute_changed(FlyString const&, Optional<String> const&, Optional<FlyString> const&) override;
virtual void children_changed() override;
virtual void children_changed(ChildrenChangedMetadata const*) override;
// https://www.w3.org/TR/html-aria/#el-textarea
virtual Optional<ARIA::Role> default_role() const override { return ARIA::Role::textbox; }

View file

@ -27,9 +27,9 @@ void HTMLTitleElement::initialize(JS::Realm& realm)
WEB_SET_PROTOTYPE_FOR_INTERFACE(HTMLTitleElement);
}
void HTMLTitleElement::children_changed()
void HTMLTitleElement::children_changed(ChildrenChangedMetadata const* metadata)
{
HTMLElement::children_changed();
HTMLElement::children_changed(metadata);
auto navigable = this->navigable();
if (navigable && navigable->is_traversable()) {
navigable->traversable_navigable()->page().client().page_did_change_title(document().title().to_byte_string());

View file

@ -24,7 +24,7 @@ private:
HTMLTitleElement(DOM::Document&, DOM::QualifiedName);
virtual void initialize(JS::Realm&) override;
virtual void children_changed() override;
virtual void children_changed(ChildrenChangedMetadata const*) override;
};
}

View file

@ -98,9 +98,9 @@ void SVGElement::inserted()
update_use_elements_that_reference_this();
}
void SVGElement::children_changed()
void SVGElement::children_changed(ChildrenChangedMetadata const* metadata)
{
Base::children_changed();
Base::children_changed(metadata);
update_use_elements_that_reference_this();
}

View file

@ -36,7 +36,7 @@ protected:
virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override;
virtual WebIDL::ExceptionOr<void> cloned(DOM::Node&, bool) const override;
virtual void children_changed() override;
virtual void children_changed(ChildrenChangedMetadata const*) override;
virtual void inserted() override;
virtual void removed_from(Node* old_parent, Node& old_root) override;

View file

@ -30,9 +30,9 @@ void SVGStyleElement::visit_edges(Cell::Visitor& visitor)
m_style_element_utils.visit_edges(visitor);
}
void SVGStyleElement::children_changed()
void SVGStyleElement::children_changed(ChildrenChangedMetadata const* metadata)
{
Base::children_changed();
Base::children_changed(metadata);
m_style_element_utils.update_a_style_block(*this);
}

View file

@ -18,7 +18,7 @@ class SVGStyleElement final : public SVGElement {
public:
virtual ~SVGStyleElement() override;
virtual void children_changed() override;
virtual void children_changed(ChildrenChangedMetadata const*) override;
virtual void inserted() override;
virtual void removed_from(Node* old_parent, Node& old_root) override;

View file

@ -30,9 +30,9 @@ GC::Ptr<Layout::Node> SVGTitleElement::create_layout_node(GC::Ref<CSS::ComputedP
return nullptr;
}
void SVGTitleElement::children_changed()
void SVGTitleElement::children_changed(ChildrenChangedMetadata const* metadata)
{
Base::children_changed();
Base::children_changed(metadata);
auto& page = document().page();
if (document().browsing_context() != &page.top_level_browsing_context())

View file

@ -20,7 +20,7 @@ private:
virtual void initialize(JS::Realm&) override;
virtual GC::Ptr<Layout::Node> create_layout_node(GC::Ref<CSS::ComputedProperties>) override;
virtual void children_changed() override;
virtual void children_changed(ChildrenChangedMetadata const*) override;
};
}