From aa9f7cc597d7c06cf2ae4c202612e63dd2bb5d4e Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Sun, 17 Jul 2022 18:14:22 +0100 Subject: [PATCH] LibWeb: Fix queuing mutation records for node removal Step 19 of node removal was missing, which allows the mutations of the descendants of the removed node to still be observed by the parent. Step 20 of node removal queued the mutation record for the removed node instead of it's parent. Since queuing takes place after the node is removed from the tree, the mutation record would be lost as the only inclusive ancestor of the node at this point is only the node itself. --- Userland/Libraries/LibWeb/DOM/Node.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Userland/Libraries/LibWeb/DOM/Node.cpp b/Userland/Libraries/LibWeb/DOM/Node.cpp index 37223854c4e..4fab9e639ac 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.cpp +++ b/Userland/Libraries/LibWeb/DOM/Node.cpp @@ -563,15 +563,23 @@ void Node::remove(bool suppress_observers) return IterationDecision::Continue; }); - // FIXME: 19. For each inclusive ancestor inclusiveAncestor of parent, and then for each registered of inclusiveAncestor’s registered observer list, - // if registered’s options["subtree"] is true, then append a new transient registered observer - // whose observer is registered’s observer, options is registered’s options, and source is registered to node’s registered observer list. + // 19. For each inclusive ancestor inclusiveAncestor of parent, and then for each registered of inclusiveAncestor’s registered observer list, + // if registered’s options["subtree"] is true, then append a new transient registered observer + // whose observer is registered’s observer, options is registered’s options, and source is registered to node’s registered observer list. + for (auto* inclusive_ancestor = parent; inclusive_ancestor; inclusive_ancestor = inclusive_ancestor->parent()) { + for (auto& registered : inclusive_ancestor->m_registered_observer_list) { + if (registered.options.subtree) { + auto transient_observer = TransientRegisteredObserver::create(registered.observer, registered.options, registered); + m_registered_observer_list.append(move(transient_observer)); + } + } + } // 20. If suppress observers flag is unset, then queue a tree mutation record for parent with « », « node », oldPreviousSibling, and oldNextSibling. if (!suppress_observers) { NonnullRefPtrVector removed_nodes; removed_nodes.append(*this); - queue_tree_mutation_record(StaticNodeList::create({}), StaticNodeList::create(move(removed_nodes)), old_previous_sibling, old_next_sibling); + parent->queue_tree_mutation_record(StaticNodeList::create({}), StaticNodeList::create(move(removed_nodes)), old_previous_sibling, old_next_sibling); } // 21. Run the children changed steps for parent.