mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 09:47:35 +00:00
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.
This commit is contained in:
parent
c732e03ea0
commit
69df94ec5c
5 changed files with 75 additions and 0 deletions
5
Tests/LibWeb/Text/expected/DOM/Element-from-point.txt
Normal file
5
Tests/LibWeb/Text/expected/DOM/Element-from-point.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Negative coordinates return null: true
|
||||||
|
Coordinates outside the viewport return null: true
|
||||||
|
<HTML id="root-element" >
|
||||||
|
<DIV id="large-box" >
|
||||||
|
<DIV id="small-box" >
|
33
Tests/LibWeb/Text/input/DOM/Element-from-point.html
Normal file
33
Tests/LibWeb/Text/input/DOM/Element-from-point.html
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html id="root-element">
|
||||||
|
<style>
|
||||||
|
#large-box {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 500px;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
background-color: magenta;
|
||||||
|
}
|
||||||
|
|
||||||
|
#small-box {
|
||||||
|
position: absolute;
|
||||||
|
top: 35px;
|
||||||
|
left: 525px;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
background-color: yellow;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="../include.js"></script>
|
||||||
|
<div id="large-box"></div><div id="small-box"></div>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
println(`Negative coordinates return null: ${document.elementFromPoint(-1, -1) === null}`);
|
||||||
|
println(`Coordinates outside the viewport return null: ${document.elementFromPoint(99999, 99999) === null}`);
|
||||||
|
printElement(document.elementFromPoint(0, 0));
|
||||||
|
printElement(document.elementFromPoint(500, 10));
|
||||||
|
printElement(document.elementFromPoint(550, 60));
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -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<Element const*>(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<Element>(); document_root_element)
|
||||||
|
return document_root_element;
|
||||||
|
|
||||||
|
// 4. Return null.
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -560,6 +560,8 @@ public:
|
||||||
void add_form_associated_element_with_form_attribute(HTML::FormAssociatedElement&);
|
void add_form_associated_element_with_form_attribute(HTML::FormAssociatedElement&);
|
||||||
void remove_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:
|
protected:
|
||||||
virtual void initialize(JS::Realm&) override;
|
virtual void initialize(JS::Realm&) override;
|
||||||
virtual void visit_edges(Cell::Visitor&) override;
|
virtual void visit_edges(Cell::Visitor&) override;
|
||||||
|
|
|
@ -116,6 +116,9 @@ interface Document : Node {
|
||||||
|
|
||||||
// https://www.w3.org/TR/web-animations-1/#extensions-to-the-document-interface
|
// https://www.w3.org/TR/web-animations-1/#extensions-to-the-document-interface
|
||||||
readonly attribute DocumentTimeline timeline;
|
readonly attribute DocumentTimeline timeline;
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/cssom-view/#extensions-to-the-document-interface
|
||||||
|
Element? elementFromPoint(double x, double y);
|
||||||
};
|
};
|
||||||
|
|
||||||
dictionary ElementCreationOptions {
|
dictionary ElementCreationOptions {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue