From 903c8860f8b4de44835cda0358154bf5d2bb936b Mon Sep 17 00:00:00 2001 From: Shannon Booth Date: Mon, 27 Jan 2025 01:16:33 +1300 Subject: [PATCH] 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. --- Libraries/LibWeb/DOM/CharacterData.cpp | 2 +- Libraries/LibWeb/DOM/Element.cpp | 4 ++-- Libraries/LibWeb/DOM/Element.h | 2 +- Libraries/LibWeb/DOM/Node.cpp | 5 +++-- Libraries/LibWeb/DOM/Node.h | 13 ++++++++++++- Libraries/LibWeb/HTML/HTMLDetailsElement.cpp | 4 ++-- Libraries/LibWeb/HTML/HTMLDetailsElement.h | 2 +- Libraries/LibWeb/HTML/HTMLMediaElement.cpp | 4 ++-- Libraries/LibWeb/HTML/HTMLMediaElement.h | 2 +- Libraries/LibWeb/HTML/HTMLOptionElement.cpp | 4 ++-- Libraries/LibWeb/HTML/HTMLOptionElement.h | 2 +- Libraries/LibWeb/HTML/HTMLScriptElement.cpp | 4 ++-- Libraries/LibWeb/HTML/HTMLScriptElement.h | 2 +- Libraries/LibWeb/HTML/HTMLSelectElement.cpp | 4 ++-- Libraries/LibWeb/HTML/HTMLSelectElement.h | 2 +- Libraries/LibWeb/HTML/HTMLStyleElement.cpp | 4 ++-- Libraries/LibWeb/HTML/HTMLStyleElement.h | 2 +- Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp | 4 ++-- Libraries/LibWeb/HTML/HTMLTextAreaElement.h | 2 +- Libraries/LibWeb/HTML/HTMLTitleElement.cpp | 4 ++-- Libraries/LibWeb/HTML/HTMLTitleElement.h | 2 +- Libraries/LibWeb/SVG/SVGElement.cpp | 4 ++-- Libraries/LibWeb/SVG/SVGElement.h | 2 +- Libraries/LibWeb/SVG/SVGStyleElement.cpp | 4 ++-- Libraries/LibWeb/SVG/SVGStyleElement.h | 2 +- Libraries/LibWeb/SVG/SVGTitleElement.cpp | 4 ++-- Libraries/LibWeb/SVG/SVGTitleElement.h | 2 +- 27 files changed, 52 insertions(+), 40 deletions(-) diff --git a/Libraries/LibWeb/DOM/CharacterData.cpp b/Libraries/LibWeb/DOM/CharacterData.cpp index ceab2f30316..c88462121f2 100644 --- a/Libraries/LibWeb/DOM/CharacterData.cpp +++ b/Libraries/LibWeb/DOM/CharacterData.cpp @@ -126,7 +126,7 @@ WebIDL::ExceptionOr CharacterData::replace_data(size_t offset, size_t coun // 12. If node’s parent is non-null, then run the children changed steps for node’s 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 diff --git a/Libraries/LibWeb/DOM/Element.cpp b/Libraries/LibWeb/DOM/Element.cpp index 3d1d2a07c8a..8d9850dc7e7 100644 --- a/Libraries/LibWeb/DOM/Element.cpp +++ b/Libraries/LibWeb/DOM/Element.cpp @@ -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); } diff --git a/Libraries/LibWeb/DOM/Element.h b/Libraries/LibWeb/DOM/Element.h index 1679b4fee57..8c4a25bc525 100644 --- a/Libraries/LibWeb/DOM/Element.h +++ b/Libraries/LibWeb/DOM/Element.h @@ -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 diff --git a/Libraries/LibWeb/DOM/Node.cpp b/Libraries/LibWeb/DOM/Node.cpp index 2ef0762e1ab..b5a624259d3 100644 --- a/Libraries/LibWeb/DOM/Node.cpp +++ b/Libraries/LibWeb/DOM/Node.cpp @@ -745,7 +745,8 @@ void Node::insert_before(GC::Ref node, GC::Ptr 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(); } diff --git a/Libraries/LibWeb/DOM/Node.h b/Libraries/LibWeb/DOM/Node.h index 16213836dd8..b40df03731f 100644 --- a/Libraries/LibWeb/DOM/Node.h +++ b/Libraries/LibWeb/DOM/Node.h @@ -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; + }; + // 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 cloned(Node&, bool) const { return {}; } diff --git a/Libraries/LibWeb/HTML/HTMLDetailsElement.cpp b/Libraries/LibWeb/HTML/HTMLDetailsElement.cpp index 46c91a21bad..1e7178ecd57 100644 --- a/Libraries/LibWeb/HTML/HTMLDetailsElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLDetailsElement.cpp @@ -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(); } diff --git a/Libraries/LibWeb/HTML/HTMLDetailsElement.h b/Libraries/LibWeb/HTML/HTMLDetailsElement.h index 89d9d7d90a5..0e9ad921f5d 100644 --- a/Libraries/LibWeb/HTML/HTMLDetailsElement.h +++ b/Libraries/LibWeb/HTML/HTMLDetailsElement.h @@ -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 const& old_value, Optional const& value, Optional const& namespace_) override; void queue_a_details_toggle_event_task(String old_state, String new_state); diff --git a/Libraries/LibWeb/HTML/HTMLMediaElement.cpp b/Libraries/LibWeb/HTML/HTMLMediaElement.cpp index 8444e37b3f6..298181e9170 100644 --- a/Libraries/LibWeb/HTML/HTMLMediaElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLMediaElement.cpp @@ -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(); diff --git a/Libraries/LibWeb/HTML/HTMLMediaElement.h b/Libraries/LibWeb/HTML/HTMLMediaElement.h index 4805c7e60f7..c64d5cc7b31 100644 --- a/Libraries/LibWeb/HTML/HTMLMediaElement.h +++ b/Libraries/LibWeb/HTML/HTMLMediaElement.h @@ -158,7 +158,7 @@ protected: virtual void attribute_changed(FlyString const& name, Optional const& old_value, Optional const& value, Optional 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. diff --git a/Libraries/LibWeb/HTML/HTMLOptionElement.cpp b/Libraries/LibWeb/HTML/HTMLOptionElement.cpp index 7d1da5a9b9e..e8dec0f8f5e 100644 --- a/Libraries/LibWeb/HTML/HTMLOptionElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLOptionElement.cpp @@ -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(); } diff --git a/Libraries/LibWeb/HTML/HTMLOptionElement.h b/Libraries/LibWeb/HTML/HTMLOptionElement.h index ae0f1a56b8f..0fd4f76e6bb 100644 --- a/Libraries/LibWeb/HTML/HTMLOptionElement.h +++ b/Libraries/LibWeb/HTML/HTMLOptionElement.h @@ -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(); diff --git a/Libraries/LibWeb/HTML/HTMLScriptElement.cpp b/Libraries/LibWeb/HTML/HTMLScriptElement.cpp index 32384801b2a..1c820564197 100644 --- a/Libraries/LibWeb/HTML/HTMLScriptElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLScriptElement.cpp @@ -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(); diff --git a/Libraries/LibWeb/HTML/HTMLScriptElement.h b/Libraries/LibWeb/HTML/HTMLScriptElement.h index f652c51d5b2..7ab40492a38 100644 --- a/Libraries/LibWeb/HTML/HTMLScriptElement.h +++ b/Libraries/LibWeb/HTML/HTMLScriptElement.h @@ -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 diff --git a/Libraries/LibWeb/HTML/HTMLSelectElement.cpp b/Libraries/LibWeb/HTML/HTMLSelectElement.cpp index d7a6891738a..42070623503 100644 --- a/Libraries/LibWeb/HTML/HTMLSelectElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLSelectElement.cpp @@ -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(); } diff --git a/Libraries/LibWeb/HTML/HTMLSelectElement.h b/Libraries/LibWeb/HTML/HTMLSelectElement.h index 7801e703f66..9f563200acf 100644 --- a/Libraries/LibWeb/HTML/HTMLSelectElement.h +++ b/Libraries/LibWeb/HTML/HTMLSelectElement.h @@ -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(); diff --git a/Libraries/LibWeb/HTML/HTMLStyleElement.cpp b/Libraries/LibWeb/HTML/HTMLStyleElement.cpp index 4d8ec7b1926..2763b6e2c64 100644 --- a/Libraries/LibWeb/HTML/HTMLStyleElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLStyleElement.cpp @@ -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); } diff --git a/Libraries/LibWeb/HTML/HTMLStyleElement.h b/Libraries/LibWeb/HTML/HTMLStyleElement.h index e5bb976e3b9..314541ddcbe 100644 --- a/Libraries/LibWeb/HTML/HTMLStyleElement.h +++ b/Libraries/LibWeb/HTML/HTMLStyleElement.h @@ -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; diff --git a/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp b/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp index d4c5ba7ce87..d21f23f05d3 100644 --- a/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp @@ -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. diff --git a/Libraries/LibWeb/HTML/HTMLTextAreaElement.h b/Libraries/LibWeb/HTML/HTMLTextAreaElement.h index 19763895aa5..ca45cd7d24a 100644 --- a/Libraries/LibWeb/HTML/HTMLTextAreaElement.h +++ b/Libraries/LibWeb/HTML/HTMLTextAreaElement.h @@ -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 const&, Optional 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 default_role() const override { return ARIA::Role::textbox; } diff --git a/Libraries/LibWeb/HTML/HTMLTitleElement.cpp b/Libraries/LibWeb/HTML/HTMLTitleElement.cpp index 0a7bc75f7e6..0cb33962c1b 100644 --- a/Libraries/LibWeb/HTML/HTMLTitleElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLTitleElement.cpp @@ -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()); diff --git a/Libraries/LibWeb/HTML/HTMLTitleElement.h b/Libraries/LibWeb/HTML/HTMLTitleElement.h index 25facd1cb62..b99cd99aae2 100644 --- a/Libraries/LibWeb/HTML/HTMLTitleElement.h +++ b/Libraries/LibWeb/HTML/HTMLTitleElement.h @@ -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; }; } diff --git a/Libraries/LibWeb/SVG/SVGElement.cpp b/Libraries/LibWeb/SVG/SVGElement.cpp index cae35e520a9..45756e3b639 100644 --- a/Libraries/LibWeb/SVG/SVGElement.cpp +++ b/Libraries/LibWeb/SVG/SVGElement.cpp @@ -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(); } diff --git a/Libraries/LibWeb/SVG/SVGElement.h b/Libraries/LibWeb/SVG/SVGElement.h index 758969da1bc..c1c1615d525 100644 --- a/Libraries/LibWeb/SVG/SVGElement.h +++ b/Libraries/LibWeb/SVG/SVGElement.h @@ -36,7 +36,7 @@ protected: virtual void attribute_changed(FlyString const& name, Optional const& old_value, Optional const& value, Optional const& namespace_) override; virtual WebIDL::ExceptionOr 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; diff --git a/Libraries/LibWeb/SVG/SVGStyleElement.cpp b/Libraries/LibWeb/SVG/SVGStyleElement.cpp index 081be93c5fc..0d33cd7caaf 100644 --- a/Libraries/LibWeb/SVG/SVGStyleElement.cpp +++ b/Libraries/LibWeb/SVG/SVGStyleElement.cpp @@ -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); } diff --git a/Libraries/LibWeb/SVG/SVGStyleElement.h b/Libraries/LibWeb/SVG/SVGStyleElement.h index c3043e89813..b6c925f7f7d 100644 --- a/Libraries/LibWeb/SVG/SVGStyleElement.h +++ b/Libraries/LibWeb/SVG/SVGStyleElement.h @@ -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; diff --git a/Libraries/LibWeb/SVG/SVGTitleElement.cpp b/Libraries/LibWeb/SVG/SVGTitleElement.cpp index 7d3e5066f30..4569774c489 100644 --- a/Libraries/LibWeb/SVG/SVGTitleElement.cpp +++ b/Libraries/LibWeb/SVG/SVGTitleElement.cpp @@ -30,9 +30,9 @@ GC::Ptr SVGTitleElement::create_layout_node(GC::Ref create_layout_node(GC::Ref) override; - virtual void children_changed() override; + virtual void children_changed(ChildrenChangedMetadata const*) override; }; }