1
0
Fork 0
mirror of https://github.com/LadybirdBrowser/ladybird.git synced 2025-06-11 18:20:43 +09:00

LibWeb: Implement "NodeIterator pre-removing steps"

These steps run when a node is about to be removed from its parent,
and adjust the position of any live NodeIterators so that they don't
point at a now-removed node.

Note that while this commit implements what's in the DOM specification,
the specification doesn't fully match what other browsers do.

Spec bug: https://github.com/whatwg/dom/issues/907
This commit is contained in:
Andreas Kling 2022-03-09 16:38:44 +01:00
parent acbdb95b0a
commit 9c6999ecf2
Notes: sideshowbarker 2024-07-17 17:40:10 +09:00
5 changed files with 91 additions and 2 deletions

View file

@ -17,6 +17,12 @@ NodeIterator::NodeIterator(Node& root)
: m_root(root)
, m_reference(root)
{
root.document().register_node_iterator({}, *this);
}
NodeIterator::~NodeIterator()
{
m_root->document().unregister_node_iterator({}, *this);
}
// https://dom.spec.whatwg.org/#dom-document-createnodeiterator
@ -160,4 +166,44 @@ JS::ThrowCompletionOr<RefPtr<Node>> NodeIterator::previous_node()
return traverse(Direction::Previous);
}
// https://dom.spec.whatwg.org/#nodeiterator-pre-removing-steps
void NodeIterator::run_pre_removing_steps(Node& to_be_removed_node)
{
// NOTE: This function implements what the DOM specification tells us to do.
// However, it's known to not match other browsers: https://github.com/whatwg/dom/issues/907
// 1. If toBeRemovedNode is not an inclusive ancestor of nodeIterators reference, or toBeRemovedNode is nodeIterators root, then return.
if (!to_be_removed_node.is_inclusive_ancestor_of(m_reference) || &to_be_removed_node == m_root)
return;
// 2. If nodeIterators pointer before reference is true, then:
if (m_pointer_before_reference) {
// 1. Let next be toBeRemovedNodes first following node that is an inclusive descendant of nodeIterators root and is not an inclusive descendant of toBeRemovedNode, and null if there is no such node.
RefPtr<Node> next = to_be_removed_node.next_in_pre_order(m_root);
while (next && (!next->is_inclusive_descendant_of(m_root) || next->is_inclusive_descendant_of(to_be_removed_node)))
next = next->next_in_pre_order(m_root);
// 2. If next is non-null, then set nodeIterators reference to next and return.
if (next) {
m_reference = *next;
return;
}
// 3. Otherwise, set nodeIterators pointer before reference to false.
m_pointer_before_reference = false;
}
// 3. Set nodeIterators reference to toBeRemovedNodes parent, if toBeRemovedNodes previous sibling is null,
if (!to_be_removed_node.previous_sibling()) {
VERIFY(to_be_removed_node.parent());
m_reference = *to_be_removed_node.parent();
} else {
// ...and to the inclusive descendant of toBeRemovedNodes previous sibling that appears last in tree order otherwise.
auto* node = to_be_removed_node.previous_sibling();
while (node->last_child())
node = node->last_child();
m_reference = *node;
}
}
}