layout: Consider transform for bounding box queries (#37871)

The recent changes that cached the Scroll Tree present an opportunity to
calculate the queries that consider transform and scroll (dubbed as post
composite queries) accurately.

This PR propose a solution for this calculation by noting the lowest
scroll tree nodes that would affect a fragment. To do this, each
fragment would store a new attribute `spatial_tree_node` -- scroll tree
node id that we could use for the query. This referencing is considered
because the scroll tree node construction is managed by the fragment
itself. Therefore it would ease the managing the possibly stale
reference and future query cache invalidation considering the
development of incremental layout.

The bounding box query then could transform the bounding content rect of
a fragment using the computed current transformation matrix.

Fixes: https://github.com/servo/servo/issues/35768
Testing: Existing and new WPT

---------

Signed-off-by: stevennovaryo <steven.novaryo@gmail.com>
Signed-off-by: Jo Steven Novaryo <jo.steven.novaryo@huawei.com>
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Jo Steven Novaryo 2025-07-30 16:13:54 +08:00 committed by GitHub
parent 37ac4ffeb4
commit 900dd8d191
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 304 additions and 146 deletions

View file

@ -253,16 +253,34 @@ impl Layout for LayoutThread {
.remove_all_web_fonts_from_stylesheet(&stylesheet);
}
/// Return the union of this node's content boxes in the coordinate space of the Document.
/// to implement `getBoundingClientRect()`.
///
/// Part of <https://drafts.csswg.org/cssom-view-1/#element-get-the-bounding-box>
/// TODO(stevennovaryo): Rename and parameterize the function, allowing padding area
/// query and possibly, query without consideration of transform.
#[servo_tracing::instrument(skip_all)]
fn query_content_box(&self, node: TrustedNodeAddress) -> Option<UntypedRect<Au>> {
let node = unsafe { ServoLayoutNode::new(&node) };
process_content_box_request(node)
let stacking_context_tree = self.stacking_context_tree.borrow();
let stacking_context_tree = stacking_context_tree
.as_ref()
.expect("Should always have a StackingContextTree for geometry queries");
process_content_box_request(stacking_context_tree, node)
}
/// Get a `Vec` of bounding boxes of this node's `Fragement`s in the coordinate space of the
/// Document. This is used to implement `getClientRects()`.
///
/// See <https://drafts.csswg.org/cssom-view/#dom-element-getclientrects>.
#[servo_tracing::instrument(skip_all)]
fn query_content_boxes(&self, node: TrustedNodeAddress) -> Vec<UntypedRect<Au>> {
let node = unsafe { ServoLayoutNode::new(&node) };
process_content_boxes_request(node)
let stacking_context_tree = self.stacking_context_tree.borrow();
let stacking_context_tree = stacking_context_tree
.as_ref()
.expect("Should always have a StackingContextTree for geometry queries");
process_content_boxes_request(stacking_context_tree, node)
}
#[servo_tracing::instrument(skip_all)]
@ -1431,12 +1449,11 @@ impl ReflowPhases {
QueryMsg::NodesFromPointQuery => {
Self::StackingContextTreeConstruction | Self::DisplayListConstruction
},
QueryMsg::ResolvedStyleQuery | QueryMsg::ScrollingAreaOrOffsetQuery => {
Self::StackingContextTreeConstruction
},
QueryMsg::ClientRectQuery |
QueryMsg::ContentBox |
QueryMsg::ContentBoxes |
QueryMsg::ResolvedStyleQuery |
QueryMsg::ScrollingAreaOrOffsetQuery => Self::StackingContextTreeConstruction,
QueryMsg::ClientRectQuery |
QueryMsg::ElementInnerOuterTextQuery |
QueryMsg::InnerWindowDimensionsQuery |
QueryMsg::OffsetParentQuery |