From 69df94ec5c86ebb1f022d01aaba747a6b0f7e2ff Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Tue, 6 Feb 2024 06:02:51 +0000 Subject: [PATCH] LibWeb: Implement `document.elementFromPoint()` This function uses our existing hit testing code to determine the topmost element at the given coordinates relative to the viewport. --- .../Text/expected/DOM/Element-from-point.txt | 5 +++ .../Text/input/DOM/Element-from-point.html | 33 +++++++++++++++++++ Userland/Libraries/LibWeb/DOM/Document.cpp | 32 ++++++++++++++++++ Userland/Libraries/LibWeb/DOM/Document.h | 2 ++ Userland/Libraries/LibWeb/DOM/Document.idl | 3 ++ 5 files changed, 75 insertions(+) create mode 100644 Tests/LibWeb/Text/expected/DOM/Element-from-point.txt create mode 100644 Tests/LibWeb/Text/input/DOM/Element-from-point.html diff --git a/Tests/LibWeb/Text/expected/DOM/Element-from-point.txt b/Tests/LibWeb/Text/expected/DOM/Element-from-point.txt new file mode 100644 index 0000000000..e4adca67de --- /dev/null +++ b/Tests/LibWeb/Text/expected/DOM/Element-from-point.txt @@ -0,0 +1,5 @@ + Negative coordinates return null: true +Coordinates outside the viewport return null: true + +
+
diff --git a/Tests/LibWeb/Text/input/DOM/Element-from-point.html b/Tests/LibWeb/Text/input/DOM/Element-from-point.html new file mode 100644 index 0000000000..827350b346 --- /dev/null +++ b/Tests/LibWeb/Text/input/DOM/Element-from-point.html @@ -0,0 +1,33 @@ + + + + +
+ + diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index 0082073eef..72dab3a7ad 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -3721,4 +3721,36 @@ void Document::remove_form_associated_element_with_form_attribute(HTML::FormAsso }); } +// https://drafts.csswg.org/cssom-view/#dom-document-elementfrompoint +Element const* Document::element_from_point(double x, double y) +{ + // 1. If either argument is negative, x is greater than the viewport width excluding the size of a rendered scroll + // bar (if any), or y is greater than the viewport height excluding the size of a rendered scroll bar (if any), or + // there is no viewport associated with the document, return null and terminate these steps. + auto viewport_rect = this->viewport_rect(); + CSSPixelPoint position { x, y }; + // FIXME: This should account for the size of the scroll bar. + if (x < 0 || y < 0 || position.x() > viewport_rect.width() || position.y() > viewport_rect.height()) + return nullptr; + + // Ensure the layout tree exists prior to hit testing. + update_layout(); + + // 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. + 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); + } + } + + // 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) + return document_root_element; + + // 4. Return null. + return nullptr; +} + } diff --git a/Userland/Libraries/LibWeb/DOM/Document.h b/Userland/Libraries/LibWeb/DOM/Document.h index 778ecb4b99..315dc64d1a 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.h +++ b/Userland/Libraries/LibWeb/DOM/Document.h @@ -560,6 +560,8 @@ public: void add_form_associated_element_with_form_attribute(HTML::FormAssociatedElement&); void remove_form_associated_element_with_form_attribute(HTML::FormAssociatedElement&); + Element const* element_from_point(double x, double y); + protected: virtual void initialize(JS::Realm&) override; virtual void visit_edges(Cell::Visitor&) override; diff --git a/Userland/Libraries/LibWeb/DOM/Document.idl b/Userland/Libraries/LibWeb/DOM/Document.idl index 75812cd320..287cc822c8 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.idl +++ b/Userland/Libraries/LibWeb/DOM/Document.idl @@ -116,6 +116,9 @@ interface Document : Node { // https://www.w3.org/TR/web-animations-1/#extensions-to-the-document-interface readonly attribute DocumentTimeline timeline; + + // https://drafts.csswg.org/cssom-view/#extensions-to-the-document-interface + Element? elementFromPoint(double x, double y); }; dictionary ElementCreationOptions {