tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 68f0638062a25c387c9c7c0441358ac508de18e6
parent 7b2ae9ebd5a9a60e001b0db1616aa190bde4a39a
Author: Glenn Watson <git@chillybin.org>
Date:   Wed, 12 Nov 2025 04:15:56 +0000

Bug 1999575 - Ensure that fractional external scroll offsets from parent nodes do not affect local snapping r=gfx-reviewers,lsalzman

Differential Revision: https://phabricator.services.mozilla.com/D272182

Diffstat:
Mgfx/wr/webrender/src/spatial_tree.rs | 78+++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Agfx/wr/wrench/reftests/snap/content-offset-ref.yaml | 6++++++
Agfx/wr/wrench/reftests/snap/content-offset.yaml | 18++++++++++++++++++
Mgfx/wr/wrench/reftests/snap/reftest.list | 1+
4 files changed, 80 insertions(+), 23 deletions(-)

diff --git a/gfx/wr/webrender/src/spatial_tree.rs b/gfx/wr/webrender/src/spatial_tree.rs @@ -116,6 +116,40 @@ impl ops::Not for VisibleFace { pub trait SpatialNodeContainer { /// Get the common information for a given spatial node fn get_node_info(&self, index: SpatialNodeIndex) -> SpatialNodeInfo; + + fn get_snapping_info( + &self, + parent_index: Option<SpatialNodeIndex> + ) -> Option<(ScaleOffset, LayoutVector2D)> { + match parent_index { + Some(parent_index) => { + let node_info = self.get_node_info(parent_index); + + match node_info.snapping_transform { + Some(snapping_transform) => { + let content_offset = match node_info.node_type { + SpatialNodeType::StickyFrame(ref info) => { + info.previously_applied_offset + } + SpatialNodeType::ScrollFrame(ref info) => { + info.external_scroll_offset + } + SpatialNodeType::ReferenceFrame(..) => { + LayoutVector2D::zero() + } + }; + Some((snapping_transform, content_offset)) + } + None => { + None + } + } + } + None => { + Some((ScaleOffset::identity(), LayoutVector2D::zero())) + } + } + } } #[cfg_attr(feature = "capture", derive(Serialize))] @@ -438,17 +472,10 @@ impl SceneSpatialTree { mut node: SceneSpatialNode, uid: SpatialNodeUid, ) -> SpatialNodeIndex { - let parent_snapping_transform = match node.parent { - Some(parent_index) => { - self.get_node_info(parent_index).snapping_transform - } - None => { - Some(ScaleOffset::identity()) - } - }; + let parent_info = self.get_snapping_info(node.parent); node.snapping_transform = calculate_snapping_transform( - parent_snapping_transform, + parent_info, &node.descriptor.node_type, ); @@ -1206,19 +1233,13 @@ impl SpatialTree { node_index: SpatialNodeIndex, scene_properties: &SceneProperties, ) { - let parent_snapping_transform = match self.get_spatial_node(node_index).parent { - Some(parent_index) => { - self.get_node_info(parent_index).snapping_transform - } - None => { - Some(ScaleOffset::identity()) - } - }; + let parent_index = self.get_spatial_node(node_index).parent; + let parent_info = self.get_snapping_info(parent_index); let node = &mut self.spatial_nodes[node_index.0 as usize]; node.snapping_transform = calculate_snapping_transform( - parent_snapping_transform, + parent_info, &node.node_type, ); @@ -1399,27 +1420,39 @@ pub fn get_external_scroll_offset<S: SpatialNodeContainer>( } fn calculate_snapping_transform( - parent_snapping_transform: Option<ScaleOffset>, + parent_info: Option<(ScaleOffset, LayoutVector2D)>, node_type: &SpatialNodeType, ) -> Option<ScaleOffset> { // We need to incorporate the parent scale/offset with the child. // If the parent does not have a scale/offset, then we know we are // not 2d axis aligned and thus do not need to snap its children // either. - let parent_scale_offset = match parent_snapping_transform { - Some(parent_snapping_transform) => parent_snapping_transform, + let (parent_scale_offset, content_fract_offset) = match parent_info { + Some((transform, content_offset)) => { + ( + transform, + LayoutVector2D::new( + content_offset.x.fract(), + content_offset.y.fract(), + ) + ) + } None => return None, }; let scale_offset = match node_type { SpatialNodeType::ReferenceFrame(ref info) => { + // Ensure that if a parent external scroll offset has a fractional component + // that this doesn't affect the snapping calculations during scene building + // (the overall scroll offset is snapped to device pixel by the spatial tree) + let origin_offset = info.origin_in_parent_reference_frame - content_fract_offset; + match info.source_transform { PropertyBinding::Value(ref value) => { // We can only get a ScaleOffset if the transform is 2d axis // aligned. match ScaleOffset::from_transform(value) { Some(scale_offset) => { - let origin_offset = info.origin_in_parent_reference_frame; scale_offset.then(&ScaleOffset::from_offset(origin_offset.to_untyped())) } None => return None, @@ -1430,7 +1463,6 @@ fn calculate_snapping_transform( // We still want to incorporate the reference frame offset however. // TODO(aosmond): Is there a better known starting point? PropertyBinding::Binding(..) => { - let origin_offset = info.origin_in_parent_reference_frame; ScaleOffset::from_offset(origin_offset.to_untyped()) } } diff --git a/gfx/wr/wrench/reftests/snap/content-offset-ref.yaml b/gfx/wr/wrench/reftests/snap/content-offset-ref.yaml @@ -0,0 +1,6 @@ +--- +root: + items: + - type: rect + bounds: [ 125, 25, 50, 50 ] + color: green diff --git a/gfx/wr/wrench/reftests/snap/content-offset.yaml b/gfx/wr/wrench/reftests/snap/content-offset.yaml @@ -0,0 +1,18 @@ +# Ensure that if a parent external scroll offset has a fractional component +# that this doesn't affect the snapping calculations during scene building +# (the overall scroll offset is snapped to device pixel by the spatial tree) +--- +root: + items: + - type: scroll-frame + bounds: [0, 0, 200, 100] + content-size: [200, 200] + scroll-offset: [0, 100] + external-scroll-offset: [0, 50.1] + items: + - type: stacking-context + transform: translate(100, 0.4) + items: + - type: rect + bounds: [ 25, 125, 50, 50 ] + color: green diff --git a/gfx/wr/wrench/reftests/snap/reftest.list b/gfx/wr/wrench/reftests/snap/reftest.list @@ -4,3 +4,4 @@ platform(linux,mac) == preserve-3d.yaml preserve-3d.png fuzzy(128,200) == subpixel-raster-root.yaml subpixel-raster-root-ref.yaml platform(linux,mac) == fractional-filter.yaml fractional-filter-ref.yaml max_surface_size(256) == 1761299.yaml 1761299.yaml +== content-offset.yaml content-offset-ref.yaml