mirror of
https://github.com/servo/servo.git
synced 2025-09-10 15:08:21 +01:00
layout: Gracefully handle script queries on nodes with uninvertible transforms (#39075)
Instead of panicking when doing a geometry script query on a node with an uninvertible transform, return a zero-sized rectangle at the untransformed position. This is similar to what Gecko and Blink do (though it seems there are some differences in positioning this zero-sized rectangle). Mostly importantly, do not panic. Testing: This change adds a new WPT crash test. Fixes: #38848. Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
4de84b0ca5
commit
efe9ea2306
4 changed files with 53 additions and 6 deletions
|
@ -1009,6 +1009,7 @@ impl BoxFragment {
|
||||||
// > If a transform function causes the current transformation matrix of an object
|
// > If a transform function causes the current transformation matrix of an object
|
||||||
// > to be non-invertible, the object and its content do not get displayed.
|
// > to be non-invertible, the object and its content do not get displayed.
|
||||||
if !reference_frame_data.transform.is_invertible() {
|
if !reference_frame_data.transform.is_invertible() {
|
||||||
|
self.clear_spatial_tree_node_including_descendants();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1705,6 +1706,29 @@ impl BoxFragment {
|
||||||
Perspective::None => None,
|
Perspective::None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clear_spatial_tree_node_including_descendants(&self) {
|
||||||
|
fn assign_spatial_tree_node_on_fragments(fragments: &[Fragment]) {
|
||||||
|
for fragment in fragments.iter() {
|
||||||
|
match fragment {
|
||||||
|
Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => {
|
||||||
|
box_fragment
|
||||||
|
.borrow()
|
||||||
|
.clear_spatial_tree_node_including_descendants();
|
||||||
|
},
|
||||||
|
Fragment::Positioning(positioning_fragment) => {
|
||||||
|
assign_spatial_tree_node_on_fragments(
|
||||||
|
&positioning_fragment.borrow().children,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*self.spatial_tree_node.borrow_mut() = None;
|
||||||
|
assign_spatial_tree_node_on_fragments(&self.children);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PositioningFragment {
|
impl PositioningFragment {
|
||||||
|
|
|
@ -60,10 +60,8 @@ fn root_transform_for_layout_node(
|
||||||
.first()
|
.first()
|
||||||
.and_then(Fragment::retrieve_box_fragment)?
|
.and_then(Fragment::retrieve_box_fragment)?
|
||||||
.borrow();
|
.borrow();
|
||||||
let scroll_tree_node_id = box_fragment
|
let scroll_tree_node_id = box_fragment.spatial_tree_node.borrow();
|
||||||
.spatial_tree_node
|
let scroll_tree_node_id = (*scroll_tree_node_id)?;
|
||||||
.borrow()
|
|
||||||
.expect("Should always have a scroll tree node when querying bounding box.");
|
|
||||||
Some(scroll_tree.cumulative_node_to_root_transform(&scroll_tree_node_id))
|
Some(scroll_tree.cumulative_node_to_root_transform(&scroll_tree_node_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +85,7 @@ pub(crate) fn process_box_area_request(
|
||||||
let Some(transform) =
|
let Some(transform) =
|
||||||
root_transform_for_layout_node(&stacking_context_tree.compositor_info.scroll_tree, node)
|
root_transform_for_layout_node(&stacking_context_tree.compositor_info.scroll_tree, node)
|
||||||
else {
|
else {
|
||||||
return Some(rect_union);
|
return Some(Rect::new(rect_union.origin, Size2D::zero()));
|
||||||
};
|
};
|
||||||
|
|
||||||
transform_au_rectangle(rect_union, transform)
|
transform_au_rectangle(rect_union, transform)
|
||||||
|
@ -107,7 +105,9 @@ pub(crate) fn process_box_areas_request(
|
||||||
let Some(transform) =
|
let Some(transform) =
|
||||||
root_transform_for_layout_node(&stacking_context_tree.compositor_info.scroll_tree, node)
|
root_transform_for_layout_node(&stacking_context_tree.compositor_info.scroll_tree, node)
|
||||||
else {
|
else {
|
||||||
return box_areas.collect();
|
return box_areas
|
||||||
|
.map(|rect| Rect::new(rect.origin, Size2D::zero()))
|
||||||
|
.collect();
|
||||||
};
|
};
|
||||||
|
|
||||||
box_areas
|
box_areas
|
||||||
|
|
7
tests/wpt/meta/MANIFEST.json
vendored
7
tests/wpt/meta/MANIFEST.json
vendored
|
@ -5819,6 +5819,13 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"uninvertible-transform-and-script-queries.html": [
|
||||||
|
"8a3c88fcb8ade4038ba47a347cf3a5375d521bd4",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"w-crossing-zero-001.html": [
|
"w-crossing-zero-001.html": [
|
||||||
"64ba0e85f24d501e4115d7e697052acb3a84f27a",
|
"64ba0e85f24d501e4115d7e697052acb3a84f27a",
|
||||||
[
|
[
|
||||||
|
|
16
tests/wpt/tests/css/css-transforms/crashtests/uninvertible-transform-and-script-queries.html
vendored
Normal file
16
tests/wpt/tests/css/css-transforms/crashtests/uninvertible-transform-and-script-queries.html
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<link rel="help" href="https://github.com/servo/servo/issues/38848">
|
||||||
|
|
||||||
|
<div style="transform: scale(0)">
|
||||||
|
<img style="height: 200px; width: 200px; border: solid;" id="img">
|
||||||
|
<div style="height: 200px; width: 200px; border: solid;" id="div"></div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
div.getBoundingClientRect();
|
||||||
|
div.getClientRects();
|
||||||
|
img.getBoundingClientRect();
|
||||||
|
img.getClientRects();
|
||||||
|
img.height;
|
||||||
|
img.width;
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue