LibWeb: Pass old parent's root to Node::removed_from()

This will allow nodes to access the root they've just been removed from.
This commit is contained in:
Andreas Kling 2025-01-23 17:37:18 +01:00 committed by Andreas Kling
commit 7269fc3e52
Notes: github-actions[bot] 2025-01-23 20:40:20 +00:00
39 changed files with 65 additions and 60 deletions

View file

@ -1089,9 +1089,9 @@ void Element::inserted()
document().element_with_name_was_added({}, *this);
}
void Element::removed_from(Node* node)
void Element::removed_from(Node* old_parent, Node& old_root)
{
Base::removed_from(node);
Base::removed_from(old_parent, old_root);
if (m_id.has_value())
document().element_with_id_was_removed({}, *this);

View file

@ -403,7 +403,7 @@ protected:
virtual void initialize(JS::Realm&) override;
virtual void inserted() override;
virtual void removed_from(Node*) override;
virtual void removed_from(Node* old_parent, Node& old_root) override;
virtual void children_changed() override;
virtual i32 default_tab_index_value() const;

View file

@ -906,9 +906,11 @@ void Node::remove(bool suppress_observers)
if (auto assigned_slot = assigned_slot_for_node(*this))
assign_slottables(*assigned_slot);
auto& parent_root = parent->root();
// 13. If parents root is a shadow root, and parent is a slot whose assigned nodes is the empty list, then run
// signal a slot change for parent.
if (parent->root().is_shadow_root() && is<HTML::HTMLSlotElement>(parent)) {
if (parent_root.is_shadow_root() && is<HTML::HTMLSlotElement>(parent)) {
auto& slot = static_cast<HTML::HTMLSlotElement&>(*parent);
if (slot.assigned_nodes_internal().is_empty())
@ -925,14 +927,14 @@ void Node::remove(bool suppress_observers)
if (has_descendent_slot) {
// 1. Run assign slottables for a tree with parents root.
assign_slottables_for_a_tree(parent->root());
assign_slottables_for_a_tree(parent_root);
// 2. Run assign slottables for a tree with node.
assign_slottables_for_a_tree(*this);
}
// 15. Run the removing steps with node and parent.
removed_from(parent);
removed_from(parent, parent_root);
// 16. Let isParentConnected be parents connected.
bool is_parent_connected = parent->is_connected();
@ -953,7 +955,7 @@ void Node::remove(bool suppress_observers)
// 18. For each shadow-including descendant descendant of node, in shadow-including tree order, then:
for_each_shadow_including_descendant([&](Node& descendant) {
// 1. Run the removing steps with descendant
descendant.removed_from(nullptr);
descendant.removed_from(nullptr, parent_root);
// 2. If descendant is custom and isParentConnected is true, then enqueue a custom element callback reaction with descendant,
// callback name "disconnectedCallback", and an empty argument list.
@ -1433,7 +1435,7 @@ void Node::inserted()
set_needs_style_update(true);
}
void Node::removed_from(Node*)
void Node::removed_from(Node*, Node&)
{
m_layout_node = nullptr;
m_paintable = nullptr;

View file

@ -261,7 +261,7 @@ public:
virtual void inserted();
virtual void post_connection();
virtual void removed_from(Node*);
virtual void removed_from(Node* old_parent, Node& old_root);
virtual void children_changed() { }
virtual void adopted_from(Document&) { }
virtual WebIDL::ExceptionOr<void> cloned(Node&, bool) const { return {}; }

View file

@ -38,11 +38,11 @@ private:
form_associated_element_was_inserted(); \
} \
\
virtual void removed_from(DOM::Node* node) override \
virtual void removed_from(DOM::Node* old_parent, DOM::Node& old_root) override \
{ \
ElementBaseClass::removed_from(node); \
ElementBaseClass::removed_from(old_parent, old_root); \
form_node_was_removed(); \
form_associated_element_was_removed(node); \
form_associated_element_was_removed(old_parent); \
} \
\
virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override \

View file

@ -40,9 +40,9 @@ void HTMLBaseElement::inserted()
set_the_frozen_base_url();
}
void HTMLBaseElement::removed_from(Node* parent)
void HTMLBaseElement::removed_from(Node* old_parent, Node& old_root)
{
HTMLElement::removed_from(parent);
HTMLElement::removed_from(old_parent, old_root);
document().update_base_element({});
}

View file

@ -23,7 +23,7 @@ public:
URL::URL const& frozen_base_url() const { return m_frozen_base_url; }
virtual void inserted() override;
virtual void removed_from(Node*) override;
virtual void removed_from(Node* old_parent, Node& old_root) override;
virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override;
private:

View file

@ -52,8 +52,9 @@ void HTMLDetailsElement::inserted()
update_shadow_tree_slots();
}
void HTMLDetailsElement::removed_from(DOM::Node*)
void HTMLDetailsElement::removed_from(DOM::Node* old_parent, DOM::Node& old_root)
{
Base::removed_from(old_parent, old_root);
set_shadow_root(nullptr);
}

View file

@ -32,7 +32,7 @@ private:
virtual void visit_edges(Cell::Visitor&) override;
virtual void inserted() override;
virtual void removed_from(DOM::Node*) override;
virtual void removed_from(DOM::Node* old_parent, DOM::Node& old_root) override;
virtual void children_changed() override;
virtual void attribute_changed(FlyString const& local_name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override;

View file

@ -41,9 +41,9 @@ void HTMLDialogElement::visit_edges(JS::Cell::Visitor& visitor)
visitor.visit(m_close_watcher);
}
void HTMLDialogElement::removed_from(Node* old_parent)
void HTMLDialogElement::removed_from(Node* old_parent, Node& old_root)
{
HTMLElement::removed_from(old_parent);
HTMLElement::removed_from(old_parent, old_root);
// 1. If removedNode's close watcher is not null, then:
if (m_close_watcher) {

View file

@ -20,7 +20,7 @@ class HTMLDialogElement final : public HTMLElement {
public:
virtual ~HTMLDialogElement() override;
virtual void removed_from(Node*) override;
virtual void removed_from(Node* old_parent, Node& old_root) override;
String return_value() const;
void set_return_value(String);

View file

@ -1286,9 +1286,9 @@ void HTMLElement::did_lose_focus()
document().editing_host_manager()->set_active_contenteditable_element(nullptr);
}
void HTMLElement::removed_from(Node* old_parent)
void HTMLElement::removed_from(Node* old_parent, Node& old_root)
{
Element::removed_from(old_parent);
Element::removed_from(old_parent, old_root);
// If removedNode's popover attribute is not in the no popover state, then run the hide popover algorithm given removedNode, false, false, and false.
if (popover().has_value())

View file

@ -116,7 +116,7 @@ public:
WebIDL::ExceptionOr<void> set_popover(Optional<String> value);
Optional<String> popover() const;
virtual void removed_from(Node*) override;
virtual void removed_from(Node* old_parent, Node& old_root) override;
enum class PopoverVisibilityState {
Hidden,

View file

@ -56,9 +56,9 @@ void HTMLFrameElement::inserted()
}
// https://html.spec.whatwg.org/multipage/obsolete.html#frames:html-element-removing-steps
void HTMLFrameElement::removed_from(DOM::Node* node)
void HTMLFrameElement::removed_from(DOM::Node* old_parent, DOM::Node& old_root)
{
Base::removed_from(node);
Base::removed_from(old_parent, old_root);
// The frame HTML element removing steps, given removedNode, are to destroy a child navigable given removedNode.
destroy_the_child_navigable();

View file

@ -25,7 +25,7 @@ private:
// ^DOM::Element
virtual void inserted() override;
virtual void removed_from(Node*) override;
virtual void removed_from(Node* old_parent, Node& old_root) override;
virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override;
virtual i32 default_tab_index_value() const override;
virtual void adjust_computed_style(CSS::ComputedProperties&) override;

View file

@ -173,9 +173,9 @@ void HTMLIFrameElement::process_the_iframe_attributes(bool initial_insertion)
}
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-iframe-element:the-iframe-element-7
void HTMLIFrameElement::removed_from(DOM::Node* node)
void HTMLIFrameElement::removed_from(DOM::Node* old_parent, DOM::Node& old_root)
{
HTMLElement::removed_from(node);
HTMLElement::removed_from(old_parent, old_root);
// When an iframe element is removed from a document, the user agent must destroy the nested navigable of the element.
destroy_the_child_navigable();

View file

@ -45,7 +45,7 @@ private:
// ^DOM::Element
virtual void post_connection() override;
virtual void removed_from(Node*) override;
virtual void removed_from(Node* old_parent, Node& old_root) override;
virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override;
virtual i32 default_tab_index_value() const override;

View file

@ -50,9 +50,9 @@ void HTMLLinkElement::initialize(JS::Realm& realm)
WEB_SET_PROTOTYPE_FOR_INTERFACE(HTMLLinkElement);
}
void HTMLLinkElement::removed_from(Node* old_parent)
void HTMLLinkElement::removed_from(Node* old_parent, Node& old_root)
{
Base::removed_from(old_parent);
Base::removed_from(old_parent, old_root);
if (m_loaded_style_sheet) {
document_or_shadow_root_style_sheets().remove_a_css_style_sheet(*m_loaded_style_sheet);
m_loaded_style_sheet = nullptr;

View file

@ -28,7 +28,7 @@ public:
virtual ~HTMLLinkElement() override;
virtual void inserted() override;
virtual void removed_from(Node* old_parent) override;
virtual void removed_from(Node* old_parent, Node& old_root) override;
String rel() const { return get_attribute_value(HTML::AttributeNames::rel); }
String type() const { return get_attribute_value(HTML::AttributeNames::type); }

View file

@ -112,9 +112,9 @@ void HTMLMediaElement::attribute_changed(FlyString const& name, Optional<String>
}
// https://html.spec.whatwg.org/multipage/media.html#playing-the-media-resource:media-element-83
void HTMLMediaElement::removed_from(DOM::Node* node)
void HTMLMediaElement::removed_from(DOM::Node* old_parent, DOM::Node& old_root)
{
Base::removed_from(node);
Base::removed_from(old_parent, old_root);
// When a media element is removed from a Document, the user agent must run the following steps:

View file

@ -157,7 +157,7 @@ protected:
virtual void visit_edges(Cell::Visitor&) override;
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*) override;
virtual void removed_from(DOM::Node* old_parent, DOM::Node& old_root) override;
virtual void children_changed() override;
// Override in subclasses to handle implementation-specific behavior when the element state changes

View file

@ -151,9 +151,9 @@ void HTMLMetaElement::inserted()
}
}
void HTMLMetaElement::removed_from(Node* parent)
void HTMLMetaElement::removed_from(Node* old_parent, Node& old_root)
{
Base::removed_from(parent);
Base::removed_from(old_parent, old_root);
update_metadata();
}

View file

@ -45,7 +45,7 @@ private:
// ^DOM::Element
virtual void inserted() override;
virtual void removed_from(Node*) override;
virtual void removed_from(Node* old_parent, Node& old_root) override;
virtual void attribute_changed(FlyString const& local_name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override;
};

View file

@ -173,8 +173,9 @@ void HTMLMeterElement::inserted()
create_shadow_tree_if_needed();
}
void HTMLMeterElement::removed_from(DOM::Node*)
void HTMLMeterElement::removed_from(DOM::Node* old_parent, DOM::Node& old_root)
{
Base::removed_from(old_parent, old_root);
set_shadow_root(nullptr);
}

View file

@ -35,7 +35,7 @@ public:
// ^HTMLElement
virtual void inserted() override;
virtual void removed_from(DOM::Node*) override;
virtual void removed_from(DOM::Node* old_parent, DOM::Node& old_root) override;
virtual void adjust_computed_style(CSS::ComputedProperties&) override;

View file

@ -36,9 +36,9 @@ void HTMLOptGroupElement::inserted()
static_cast<HTMLSelectElement&>(*parent()).update_selectedness();
}
void HTMLOptGroupElement::removed_from(Node* old_parent)
void HTMLOptGroupElement::removed_from(Node* old_parent, Node& old_root)
{
Base::removed_from(old_parent);
Base::removed_from(old_parent, old_root);
// The optgroup HTML element removing steps, given removedNode and oldParent, are:
// 1. If oldParent is a select element and removedNode has an option child, then run oldParent's selectedness setting algorithm.

View file

@ -25,7 +25,7 @@ private:
HTMLOptGroupElement(DOM::Document&, DOM::QualifiedName);
virtual void initialize(JS::Realm&) override;
virtual void removed_from(Node*) override;
virtual void removed_from(Node* old_parent, Node& old_root) override;
virtual void inserted() override;
};

View file

@ -232,9 +232,9 @@ void HTMLOptionElement::inserted()
static_cast<HTMLSelectElement&>(*parent()->parent()).update_selectedness();
}
void HTMLOptionElement::removed_from(Node* old_parent)
void HTMLOptionElement::removed_from(Node* old_parent, Node& old_root)
{
Base::removed_from(old_parent);
Base::removed_from(old_parent, old_root);
// The option HTML element removing steps, given removedNode and oldParent, are:
// 1. If oldParent is a select element, or oldParent is an optgroup element whose parent is a select element,

View file

@ -51,7 +51,7 @@ private:
virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override;
virtual void inserted() override;
virtual void removed_from(Node*) override;
virtual void removed_from(Node* old_parent, Node& old_root) override;
virtual void children_changed() override;
void ask_for_a_reset();

View file

@ -95,8 +95,9 @@ void HTMLProgressElement::inserted()
create_shadow_tree_if_needed();
}
void HTMLProgressElement::removed_from(DOM::Node*)
void HTMLProgressElement::removed_from(DOM::Node* old_parent, DOM::Node& old_root)
{
Base::removed_from(old_parent, old_root);
set_shadow_root(nullptr);
}

View file

@ -29,7 +29,7 @@ public:
// ^HTMLElement
virtual void inserted() override;
virtual void removed_from(DOM::Node*) override;
virtual void removed_from(DOM::Node* old_parent, DOM::Node& old_root) override;
virtual void adjust_computed_style(CSS::ComputedProperties&) override;

View file

@ -47,10 +47,10 @@ void HTMLSourceElement::inserted()
}
// https://html.spec.whatwg.org/multipage/embedded-content.html#the-source-element:the-source-element-16
void HTMLSourceElement::removed_from(DOM::Node* old_parent)
void HTMLSourceElement::removed_from(DOM::Node* old_parent, DOM::Node& old_root)
{
// The source HTML element removing steps, given removedNode and oldParent, are:
Base::removed_from(old_parent);
Base::removed_from(old_parent, old_root);
// FIXME: 1. If removedNode's next sibling was an img element and oldParent is a picture element, then, count this as a
// relevant mutation for the img element.

View file

@ -23,7 +23,7 @@ private:
virtual void initialize(JS::Realm&) override;
virtual void inserted() override;
virtual void removed_from(DOM::Node*) override;
virtual void removed_from(DOM::Node* old_parent, DOM::Node& old_root) override;
};
}

View file

@ -44,10 +44,10 @@ void HTMLStyleElement::inserted()
Base::inserted();
}
void HTMLStyleElement::removed_from(Node* old_parent)
void HTMLStyleElement::removed_from(Node* old_parent, Node& old_root)
{
m_style_element_utils.update_a_style_block(*this);
Base::removed_from(old_parent);
Base::removed_from(old_parent, old_root);
}
// https://html.spec.whatwg.org/multipage/semantics.html#dom-style-disabled

View file

@ -21,7 +21,7 @@ public:
virtual void children_changed() override;
virtual void inserted() override;
virtual void removed_from(Node*) override;
virtual void removed_from(Node* old_parent, Node& old_root) override;
bool disabled();
void set_disabled(bool disabled);

View file

@ -128,9 +128,9 @@ void SVGElement::update_use_elements_that_reference_this()
});
}
void SVGElement::removed_from(Node* parent)
void SVGElement::removed_from(Node* old_parent, Node& old_root)
{
Base::removed_from(parent);
Base::removed_from(old_parent, old_root);
remove_from_use_element_that_reference_this();
}

View file

@ -38,7 +38,7 @@ protected:
virtual WebIDL::ExceptionOr<void> cloned(DOM::Node&, bool) const override;
virtual void children_changed() override;
virtual void inserted() override;
virtual void removed_from(Node*) override;
virtual void removed_from(Node* old_parent, Node& old_root) override;
void update_use_elements_that_reference_this();
void remove_from_use_element_that_reference_this();

View file

@ -42,10 +42,10 @@ void SVGStyleElement::inserted()
Base::inserted();
}
void SVGStyleElement::removed_from(Node* old_parent)
void SVGStyleElement::removed_from(Node* old_parent, Node& old_root)
{
m_style_element_utils.update_a_style_block(*this);
Base::removed_from(old_parent);
Base::removed_from(old_parent, old_root);
}
// https://www.w3.org/TR/cssom/#dom-linkstyle-sheet

View file

@ -20,7 +20,7 @@ public:
virtual void children_changed() override;
virtual void inserted() override;
virtual void removed_from(Node*) override;
virtual void removed_from(Node* old_parent, Node& old_root) override;
CSS::CSSStyleSheet* sheet();
CSS::CSSStyleSheet const* sheet() const;