diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index d681295cb0c..7ab4c8f66e5 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -190,6 +190,7 @@ set(SOURCES DOM/StyleElementUtils.cpp DOM/Text.cpp DOM/TreeWalker.cpp + DOM/Utils.cpp DOM/XMLDocument.cpp DOMParsing/XMLSerializer.cpp DOMURL/DOMURL.cpp diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index db813328f27..4c53deb285d 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -1914,7 +1914,7 @@ void Document::update_active_element() Node* candidate = focused_element(); // 2. Set candidate to the result of retargeting candidate against this DocumentOrShadowRoot. - candidate = retarget(candidate, this); + candidate = verify_cast(retarget(candidate, this)); // 3. If candidate's root is not this DocumentOrShadowRoot, then return null. if (&candidate->root() != this) { diff --git a/Userland/Libraries/LibWeb/DOM/EventDispatcher.cpp b/Userland/Libraries/LibWeb/DOM/EventDispatcher.cpp index f93223062f6..2ffa115579d 100644 --- a/Userland/Libraries/LibWeb/DOM/EventDispatcher.cpp +++ b/Userland/Libraries/LibWeb/DOM/EventDispatcher.cpp @@ -196,7 +196,7 @@ bool EventDispatcher::dispatch(JS::NonnullGCPtr target, Event& even JS::GCPtr activation_target; // 4. Let relatedTarget be the result of retargeting event’s relatedTarget against target. - JS::GCPtr related_target = retarget(event.related_target(), target); + JS::GCPtr related_target = retarget(event.related_target(), target); bool clear_targets = false; // 5. If target is not relatedTarget or target is event’s relatedTarget, then: @@ -206,7 +206,7 @@ bool EventDispatcher::dispatch(JS::NonnullGCPtr target, Event& even // 2. For each touchTarget of event’s touch target list, append the result of retargeting touchTarget against target to touchTargets. for (auto& touch_target : event.touch_target_list()) { - touch_targets.append(retarget(touch_target, target)); + touch_targets.append(retarget(touch_target, target)); } // 3. Append to an event path with event, target, targetOverride, relatedTarget, touchTargets, and false. @@ -253,14 +253,14 @@ bool EventDispatcher::dispatch(JS::NonnullGCPtr target, Event& even slottable = parent; // 3. Let relatedTarget be the result of retargeting event’s relatedTarget against parent. - related_target = retarget(event.related_target(), parent); + related_target = retarget(event.related_target(), parent); // 4. Let touchTargets be a new list. touch_targets.clear(); // 5. For each touchTarget of event’s touch target list, append the result of retargeting touchTarget against parent to touchTargets. for (auto& touch_target : event.touch_target_list()) { - touch_targets.append(retarget(touch_target, parent)); + touch_targets.append(retarget(touch_target, parent)); } // 6. If parent is a Window object, or parent is a node and target’s root is a shadow-including inclusive ancestor of parent, then: diff --git a/Userland/Libraries/LibWeb/DOM/Utils.cpp b/Userland/Libraries/LibWeb/DOM/Utils.cpp new file mode 100644 index 00000000000..5cf5f011a28 --- /dev/null +++ b/Userland/Libraries/LibWeb/DOM/Utils.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020, Luke Wilde + * Copyright (c) 2024, circl + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace Web::DOM { + +// https://dom.spec.whatwg.org/#retarget +EventTarget* retarget(EventTarget* a, EventTarget* b) +{ + // To retarget an object A against an object B, repeat these steps until they return an object: + for (;;) { + // 1. If one of the following is true then return A. + // - A is not a node + if (!is(a)) + return a; + + // - A’s root is not a shadow root + auto* a_node = verify_cast(a); + auto& a_root = a_node->root(); + if (!is(a_root)) + return a; + + // - B is a node and A’s root is a shadow-including inclusive ancestor of B + if (is(b) && a_root.is_shadow_including_inclusive_ancestor_of(verify_cast(*b))) + return a; + + // 2. Set A to A’s root’s host. + auto& a_shadow_root = verify_cast(a_root); + a = a_shadow_root.host(); + } +} + +} diff --git a/Userland/Libraries/LibWeb/DOM/Utils.h b/Userland/Libraries/LibWeb/DOM/Utils.h index 5ba28e173da..416e532c6e2 100644 --- a/Userland/Libraries/LibWeb/DOM/Utils.h +++ b/Userland/Libraries/LibWeb/DOM/Utils.h @@ -7,42 +7,10 @@ #pragma once -#include -#include +#include namespace Web::DOM { -// https://dom.spec.whatwg.org/#retarget -inline EventTarget* retarget_impl(EventTarget* a, EventTarget* b) -{ - // To retarget an object A against an object B, repeat these steps until they return an object: - for (;;) { - // 1. If one of the following is true then return A. - // - A is not a node - if (!is(a)) - return a; - - // - A’s root is not a shadow root - auto* a_node = verify_cast(a); - auto& a_root = a_node->root(); - if (!is(a_root)) - return a; - - // - B is a node and A’s root is a shadow-including inclusive ancestor of B - if (is(b) && a_root.is_shadow_including_inclusive_ancestor_of(verify_cast(*b))) - return a; - - // 2. Set A to A’s root’s host. - auto& a_shadow_root = verify_cast(a_root); - a = a_shadow_root.host(); - } -} - -// https://dom.spec.whatwg.org/#retarget -template -T* retarget(T* a, T* b) -{ - return static_cast(retarget_impl(a, b)); -} +EventTarget* retarget(EventTarget* a, EventTarget* b); }