From ff48b7333cd608f36c5841618dd74d2126cfaac2 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Wed, 29 Nov 2023 18:22:16 -0500 Subject: [PATCH] LibWeb: Remove shadow roots from elements that are removed from the DOM We currently create a shadow tree once for each DOM element that renders with a shadow tree (e.g. ,
). If such an element is removed from the DOM, we must remove its shadow tree. Otherwise, the shadow tree will refer to the old document in perpetuity. If the node is added back to a DOM, then recreate the shadow tree. --- .../expected/HTML/set-innerHTML-details.txt | 1 + .../expected/HTML/set-innerHTML-input.txt | 1 + .../expected/HTML/set-innerHTML-textarea.txt | 1 + .../input/HTML/set-innerHTML-details.html | 9 +++++++ .../Text/input/HTML/set-innerHTML-input.html | 9 +++++++ .../input/HTML/set-innerHTML-textarea.html | 9 +++++++ .../LibWeb/HTML/HTMLDetailsElement.cpp | 24 +++++++++++++++++-- .../LibWeb/HTML/HTMLDetailsElement.h | 4 +++- .../LibWeb/HTML/HTMLInputElement.cpp | 5 ++++ .../Libraries/LibWeb/HTML/HTMLInputElement.h | 1 + .../LibWeb/HTML/HTMLTextAreaElement.cpp | 5 ++++ .../LibWeb/HTML/HTMLTextAreaElement.h | 1 + 12 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/HTML/set-innerHTML-details.txt create mode 100644 Tests/LibWeb/Text/expected/HTML/set-innerHTML-input.txt create mode 100644 Tests/LibWeb/Text/expected/HTML/set-innerHTML-textarea.txt create mode 100644 Tests/LibWeb/Text/input/HTML/set-innerHTML-details.html create mode 100644 Tests/LibWeb/Text/input/HTML/set-innerHTML-input.html create mode 100644 Tests/LibWeb/Text/input/HTML/set-innerHTML-textarea.html diff --git a/Tests/LibWeb/Text/expected/HTML/set-innerHTML-details.txt b/Tests/LibWeb/Text/expected/HTML/set-innerHTML-details.txt new file mode 100644 index 0000000000..d489e8ca64 --- /dev/null +++ b/Tests/LibWeb/Text/expected/HTML/set-innerHTML-details.txt @@ -0,0 +1 @@ +
diff --git a/Tests/LibWeb/Text/expected/HTML/set-innerHTML-input.txt b/Tests/LibWeb/Text/expected/HTML/set-innerHTML-input.txt new file mode 100644 index 0000000000..57b77fa2bb --- /dev/null +++ b/Tests/LibWeb/Text/expected/HTML/set-innerHTML-input.txt @@ -0,0 +1 @@ + diff --git a/Tests/LibWeb/Text/expected/HTML/set-innerHTML-textarea.txt b/Tests/LibWeb/Text/expected/HTML/set-innerHTML-textarea.txt new file mode 100644 index 0000000000..4c7361e8c1 --- /dev/null +++ b/Tests/LibWeb/Text/expected/HTML/set-innerHTML-textarea.txt @@ -0,0 +1 @@ + diff --git a/Tests/LibWeb/Text/input/HTML/set-innerHTML-details.html b/Tests/LibWeb/Text/input/HTML/set-innerHTML-details.html new file mode 100644 index 0000000000..921b0c7b00 --- /dev/null +++ b/Tests/LibWeb/Text/input/HTML/set-innerHTML-details.html @@ -0,0 +1,9 @@ +
+ + diff --git a/Tests/LibWeb/Text/input/HTML/set-innerHTML-input.html b/Tests/LibWeb/Text/input/HTML/set-innerHTML-input.html new file mode 100644 index 0000000000..32e9c29681 --- /dev/null +++ b/Tests/LibWeb/Text/input/HTML/set-innerHTML-input.html @@ -0,0 +1,9 @@ +
+ + diff --git a/Tests/LibWeb/Text/input/HTML/set-innerHTML-textarea.html b/Tests/LibWeb/Text/input/HTML/set-innerHTML-textarea.html new file mode 100644 index 0000000000..a9195fe0ed --- /dev/null +++ b/Tests/LibWeb/Text/input/HTML/set-innerHTML-textarea.html @@ -0,0 +1,9 @@ +
+ + diff --git a/Userland/Libraries/LibWeb/HTML/HTMLDetailsElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLDetailsElement.cpp index aa1b4dc399..23110e1ebc 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLDetailsElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLDetailsElement.cpp @@ -39,8 +39,17 @@ void HTMLDetailsElement::initialize(JS::Realm& realm) { Base::initialize(realm); set_prototype(&Bindings::ensure_web_prototype(realm, "HTMLDetailsElement"_fly_string)); +} - create_shadow_tree(realm).release_value_but_fixme_should_propagate_errors(); +void HTMLDetailsElement::inserted() +{ + create_shadow_tree_if_needed().release_value_but_fixme_should_propagate_errors(); + update_shadow_tree_slots(); +} + +void HTMLDetailsElement::removed_from(DOM::Node*) +{ + set_shadow_root(nullptr); } void HTMLDetailsElement::attribute_changed(FlyString const& name, Optional const& value) @@ -107,8 +116,13 @@ void HTMLDetailsElement::queue_a_details_toggle_event_task(String old_state, Str } // https://html.spec.whatwg.org/#the-details-and-summary-elements -WebIDL::ExceptionOr HTMLDetailsElement::create_shadow_tree(JS::Realm& realm) +WebIDL::ExceptionOr HTMLDetailsElement::create_shadow_tree_if_needed() { + if (shadow_root_internal()) + return {}; + + auto& realm = this->realm(); + // The element is also expected to have an internal shadow tree with two slots. auto shadow_root = heap().allocate(realm, document(), *this, Bindings::ShadowRootMode::Closed); shadow_root->set_slot_assignment(Bindings::SlotAssignmentMode::Manual); @@ -130,6 +144,9 @@ WebIDL::ExceptionOr HTMLDetailsElement::create_shadow_tree(JS::Realm& real void HTMLDetailsElement::update_shadow_tree_slots() { + if (!shadow_root_internal()) + return; + Vector summary_assignment; Vector descendants_assignment; @@ -159,6 +176,9 @@ void HTMLDetailsElement::update_shadow_tree_slots() // https://html.spec.whatwg.org/#the-details-and-summary-elements:the-details-element-6 void HTMLDetailsElement::update_shadow_tree_style() { + if (!shadow_root_internal()) + return; + if (has_attribute(HTML::AttributeNames::open)) { MUST(m_descendants_slot->set_attribute(HTML::AttributeNames::style, R"~~~( display: block; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLDetailsElement.h b/Userland/Libraries/LibWeb/HTML/HTMLDetailsElement.h index 0f18522475..2c4fb68b39 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLDetailsElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLDetailsElement.h @@ -31,12 +31,14 @@ private: virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; + virtual void inserted() override; + virtual void removed_from(DOM::Node*) override; virtual void children_changed() override; virtual void attribute_changed(FlyString const& name, Optional const& value) override; void queue_a_details_toggle_event_task(String old_state, String new_state); - WebIDL::ExceptionOr create_shadow_tree(JS::Realm&); + WebIDL::ExceptionOr create_shadow_tree_if_needed(); void update_shadow_tree_slots(); void update_shadow_tree_style(); diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp index 9533cc6c13..e3113f8d3e 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp @@ -1003,6 +1003,11 @@ void HTMLInputElement::form_associated_element_was_inserted() create_shadow_tree_if_needed(); } +void HTMLInputElement::form_associated_element_was_removed(DOM::Node*) +{ + set_shadow_root(nullptr); +} + // https://html.spec.whatwg.org/multipage/input.html#radio-button-group static bool is_in_same_radio_button_group(HTML::HTMLInputElement const& a, HTML::HTMLInputElement const& b) { diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h index 8ccaf0f751..2c381a9c51 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h @@ -139,6 +139,7 @@ public: virtual void reset_algorithm() override; virtual void form_associated_element_was_inserted() override; + virtual void form_associated_element_was_removed(DOM::Node*) override; // ^HTMLElement // https://html.spec.whatwg.org/multipage/forms.html#category-label diff --git a/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp index f671dce3e5..deb4e8da92 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp @@ -91,6 +91,11 @@ void HTMLTextAreaElement::form_associated_element_was_inserted() create_shadow_tree_if_needed(); } +void HTMLTextAreaElement::form_associated_element_was_removed(DOM::Node*) +{ + set_shadow_root(nullptr); +} + void HTMLTextAreaElement::create_shadow_tree_if_needed() { if (shadow_root_internal()) diff --git a/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.h b/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.h index aba64f05c4..6edb0d485e 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLTextAreaElement.h @@ -62,6 +62,7 @@ public: virtual void reset_algorithm() override; virtual void form_associated_element_was_inserted() override; + virtual void form_associated_element_was_removed(DOM::Node*) override; virtual void children_changed() override;