From 88ad871e2b4548f26e1f48e80df93c8d6fd1b4ba Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Tue, 13 Feb 2024 23:39:22 +0100 Subject: [PATCH] LibWeb: Do paint-order traversal in Document::element_from_point() Specify callback for hit-test function to identify closest DOM element, excluding text nodes. Add a previously failing test case. --- .../expected/DOM/Element-from-point-2.txt | 1 + .../Text/input/DOM/Element-from-point-2.html | 36 +++++++++++++++++++ Userland/Libraries/LibWeb/DOM/Document.cpp | 15 +++++--- 3 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/DOM/Element-from-point-2.txt create mode 100644 Tests/LibWeb/Text/input/DOM/Element-from-point-2.html diff --git a/Tests/LibWeb/Text/expected/DOM/Element-from-point-2.txt b/Tests/LibWeb/Text/expected/DOM/Element-from-point-2.txt new file mode 100644 index 0000000000..04c77c2e22 --- /dev/null +++ b/Tests/LibWeb/Text/expected/DOM/Element-from-point-2.txt @@ -0,0 +1 @@ +hello
diff --git a/Tests/LibWeb/Text/input/DOM/Element-from-point-2.html b/Tests/LibWeb/Text/input/DOM/Element-from-point-2.html new file mode 100644 index 0000000000..c6936d565e --- /dev/null +++ b/Tests/LibWeb/Text/input/DOM/Element-from-point-2.html @@ -0,0 +1,36 @@ + + +
+
+
hello
+ + diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index 035c5c923c..dd52f5fff9 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -3793,12 +3793,19 @@ Element const* Document::element_from_point(double x, double y) // 2. If there is a box in the viewport that would be a target for hit testing at coordinates x,y, when applying the transforms // that apply to the descendants of the viewport, return the associated element and terminate these steps. + Optional hit_test_result; if (auto const* paintable_box = this->paintable_box(); paintable_box) { - if (auto result = paintable_box->hit_test(position, Painting::HitTestType::Exact); result.has_value()) { - if (auto* dom_node = result->dom_node(); dom_node && dom_node->is_element()) - return static_cast(dom_node); - } + (void)paintable_box->hit_test(position, Painting::HitTestType::Exact, [&](Painting::HitTestResult result) { + auto* dom_node = result.dom_node(); + if (dom_node && dom_node->is_element()) { + hit_test_result = result; + return Painting::TraversalDecision::Break; + } + return Painting::TraversalDecision::Continue; + }); } + if (hit_test_result.has_value()) + return static_cast(hit_test_result->dom_node()); // 3. If the document has a root element, return the root element and terminate these steps. if (auto const* document_root_element = first_child_of_type(); document_root_element)