mirror of
https://github.com/RGBCube/serenity
synced 2025-07-23 15:47:36 +00:00
LibWeb: Do paint-order traversal in Document::elements_from_point()
Elements are now collected according to paint order as spec says, replacing the depth-first traversal of the paint tree with hit-testing on each box. This change resolves a FIXME in an existing test and adds a new previously non-working test.
This commit is contained in:
parent
9c99182b1e
commit
9d2809146f
7 changed files with 68 additions and 20 deletions
4
Tests/LibWeb/Text/expected/DOM/Elements-from-point-2.txt
Normal file
4
Tests/LibWeb/Text/expected/DOM/Elements-from-point-2.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
hello <DIV id="c" >
|
||||||
|
<DIV id="b" >
|
||||||
|
<DIV id="a" >
|
||||||
|
<HTML >
|
1
Tests/LibWeb/Text/expected/DOM/Elements-from-point-3.txt
Normal file
1
Tests/LibWeb/Text/expected/DOM/Elements-from-point-3.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Some text Elements at point 30, 20: p < div < body < html
|
|
@ -3,11 +3,9 @@ Coordinates outside the viewport return empty array: true
|
||||||
== Elements at (500, 10) ==
|
== Elements at (500, 10) ==
|
||||||
<DIV id="large-box" >
|
<DIV id="large-box" >
|
||||||
<HTML >
|
<HTML >
|
||||||
== FIXME: Elements at (550, 60) ==
|
== Elements at (550, 60) ==
|
||||||
<DIV id="small-box" >
|
<DIV id="small-box" >
|
||||||
<PRE id="out" >
|
|
||||||
<PRE id="out" >
|
|
||||||
<DIV id="large-box" >
|
<DIV id="large-box" >
|
||||||
<DIV id="small-box" >
|
|
||||||
<PRE id="out" >
|
<PRE id="out" >
|
||||||
|
<BODY >
|
||||||
<HTML >
|
<HTML >
|
||||||
|
|
37
Tests/LibWeb/Text/input/DOM/Elements-from-point-2.html
Normal file
37
Tests/LibWeb/Text/input/DOM/Elements-from-point-2.html
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<style>
|
||||||
|
.box {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
#a {
|
||||||
|
background-color: magenta;
|
||||||
|
z-index: 1;
|
||||||
|
transform: translate(110px, 10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#b {
|
||||||
|
background-color: mediumaquamarine;
|
||||||
|
z-index: 2;
|
||||||
|
transform: translate(120px, 20px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#c {
|
||||||
|
background-color: greenyellow;
|
||||||
|
z-index: 3;
|
||||||
|
transform: translate(130px, 30px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id="a" class="box"></div>
|
||||||
|
<div id="b" class="box"></div>
|
||||||
|
<div id="c" class="box">hello</div>
|
||||||
|
<script src="../include.js"></script>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
for (const element of document.elementsFromPoint(150, 50)) {
|
||||||
|
printElement(element)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
18
Tests/LibWeb/Text/input/DOM/Elements-from-point-3.html
Normal file
18
Tests/LibWeb/Text/input/DOM/Elements-from-point-3.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<div>
|
||||||
|
<p>Some text</p>
|
||||||
|
</div>
|
||||||
|
<p>Elements at point 30, 20:</p>
|
||||||
|
<div id="output"></div>
|
||||||
|
<script src="../include.js"></script>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
let output = document.getElementById("output");
|
||||||
|
let elements = document.elementsFromPoint(30, 20);
|
||||||
|
elements.forEach((elt, i) => {
|
||||||
|
output.textContent += elt.localName;
|
||||||
|
if (i < elements.length - 1) {
|
||||||
|
output.textContent += " < ";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -32,15 +32,9 @@
|
||||||
for (let elem of document.elementsFromPoint(500, 10)) {
|
for (let elem of document.elementsFromPoint(500, 10)) {
|
||||||
printElement(elem);
|
printElement(elem);
|
||||||
}
|
}
|
||||||
println("== FIXME: Elements at (550, 60) ==")
|
println("== Elements at (550, 60) ==")
|
||||||
for (let elem of document.elementsFromPoint(550, 60)) {
|
for (let elem of document.elementsFromPoint(550, 60)) {
|
||||||
printElement(elem);
|
printElement(elem);
|
||||||
}
|
}
|
||||||
// FIXME: 550, 60 is supposed to print the following, but the algorithm is wrong.
|
|
||||||
// <DIV id="small-box" >
|
|
||||||
// <DIV id="large-box" >
|
|
||||||
// <PRE id="out" >
|
|
||||||
// <BODY >
|
|
||||||
// <HTML >
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -3829,16 +3829,12 @@ Vector<JS::NonnullGCPtr<Element>> Document::elements_from_point(double x, double
|
||||||
// 3. For each box in the viewport, in paint order, starting with the topmost box, that would be a target for
|
// 3. For each box in the viewport, in paint order, starting with the topmost box, that would be a target for
|
||||||
// hit testing at coordinates x,y even if nothing would be overlapping it, when applying the transforms that
|
// hit testing at coordinates x,y even if nothing would be overlapping it, when applying the transforms that
|
||||||
// apply to the descendants of the viewport, append the associated element to sequence.
|
// apply to the descendants of the viewport, append the associated element to sequence.
|
||||||
// FIXME: Paintable box tree order is not the same as paint order. We need a helper to traverse the paint tree in
|
|
||||||
// paint order with a custom callback.
|
|
||||||
if (auto const* paintable_box = this->paintable_box(); paintable_box) {
|
if (auto const* paintable_box = this->paintable_box(); paintable_box) {
|
||||||
paintable_box->for_each_in_inclusive_subtree_of_type<Painting::PaintableBox>([&](auto& paintable_box) {
|
(void)paintable_box->hit_test(position, Painting::HitTestType::Exact, [&](Painting::HitTestResult result) {
|
||||||
if (auto result = paintable_box.hit_test(position, Painting::HitTestType::Exact); result.has_value()) {
|
auto* dom_node = result.dom_node();
|
||||||
if (auto* dom_node = result->dom_node(); dom_node && dom_node->is_element())
|
if (dom_node && dom_node->is_element())
|
||||||
sequence.append(*static_cast<Element*>(dom_node));
|
sequence.append(*static_cast<Element*>(dom_node));
|
||||||
return Painting::TraversalDecision::Continue;
|
return Painting::TraversalDecision::Continue;
|
||||||
}
|
|
||||||
return Painting::TraversalDecision::SkipChildrenAndContinue;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue