diff --git a/Cargo.lock b/Cargo.lock index 866ff0b2839..9e14cbbf70b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6634,7 +6634,7 @@ dependencies = [ [[package]] name = "selectors" version = "0.28.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#1707256dd825f14e98161a49fdd6749f8ca0d506" +source = "git+https://github.com/servo/stylo?rev=refs%2Fpull%2F190%2Fhead#f63374493723974a6ec303f30a647ca22c3ae07b" dependencies = [ "bitflags 2.9.1", "cssparser", @@ -6929,7 +6929,7 @@ dependencies = [ [[package]] name = "servo_arc" version = "0.4.1" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#1707256dd825f14e98161a49fdd6749f8ca0d506" +source = "git+https://github.com/servo/stylo?rev=refs%2Fpull%2F190%2Fhead#f63374493723974a6ec303f30a647ca22c3ae07b" dependencies = [ "serde", "stable_deref_trait", @@ -7390,7 +7390,7 @@ dependencies = [ [[package]] name = "stylo" version = "0.3.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#1707256dd825f14e98161a49fdd6749f8ca0d506" +source = "git+https://github.com/servo/stylo?rev=refs%2Fpull%2F190%2Fhead#f63374493723974a6ec303f30a647ca22c3ae07b" dependencies = [ "app_units", "arrayvec", @@ -7448,7 +7448,7 @@ dependencies = [ [[package]] name = "stylo_atoms" version = "0.3.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#1707256dd825f14e98161a49fdd6749f8ca0d506" +source = "git+https://github.com/servo/stylo?rev=refs%2Fpull%2F190%2Fhead#f63374493723974a6ec303f30a647ca22c3ae07b" dependencies = [ "string_cache", "string_cache_codegen", @@ -7457,12 +7457,12 @@ dependencies = [ [[package]] name = "stylo_config" version = "0.3.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#1707256dd825f14e98161a49fdd6749f8ca0d506" +source = "git+https://github.com/servo/stylo?rev=refs%2Fpull%2F190%2Fhead#f63374493723974a6ec303f30a647ca22c3ae07b" [[package]] name = "stylo_derive" version = "0.3.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#1707256dd825f14e98161a49fdd6749f8ca0d506" +source = "git+https://github.com/servo/stylo?rev=refs%2Fpull%2F190%2Fhead#f63374493723974a6ec303f30a647ca22c3ae07b" dependencies = [ "darling", "proc-macro2", @@ -7474,7 +7474,7 @@ dependencies = [ [[package]] name = "stylo_dom" version = "0.3.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#1707256dd825f14e98161a49fdd6749f8ca0d506" +source = "git+https://github.com/servo/stylo?rev=refs%2Fpull%2F190%2Fhead#f63374493723974a6ec303f30a647ca22c3ae07b" dependencies = [ "bitflags 2.9.1", "stylo_malloc_size_of", @@ -7483,7 +7483,7 @@ dependencies = [ [[package]] name = "stylo_malloc_size_of" version = "0.3.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#1707256dd825f14e98161a49fdd6749f8ca0d506" +source = "git+https://github.com/servo/stylo?rev=refs%2Fpull%2F190%2Fhead#f63374493723974a6ec303f30a647ca22c3ae07b" dependencies = [ "app_units", "cssparser", @@ -7500,12 +7500,12 @@ dependencies = [ [[package]] name = "stylo_static_prefs" version = "0.3.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#1707256dd825f14e98161a49fdd6749f8ca0d506" +source = "git+https://github.com/servo/stylo?rev=refs%2Fpull%2F190%2Fhead#f63374493723974a6ec303f30a647ca22c3ae07b" [[package]] name = "stylo_traits" version = "0.3.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#1707256dd825f14e98161a49fdd6749f8ca0d506" +source = "git+https://github.com/servo/stylo?rev=refs%2Fpull%2F190%2Fhead#f63374493723974a6ec303f30a647ca22c3ae07b" dependencies = [ "app_units", "bitflags 2.9.1", @@ -7914,7 +7914,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "to_shmem" version = "0.2.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#1707256dd825f14e98161a49fdd6749f8ca0d506" +source = "git+https://github.com/servo/stylo?rev=refs%2Fpull%2F190%2Fhead#f63374493723974a6ec303f30a647ca22c3ae07b" dependencies = [ "cssparser", "servo_arc", @@ -7927,7 +7927,7 @@ dependencies = [ [[package]] name = "to_shmem_derive" version = "0.1.0" -source = "git+https://github.com/servo/stylo?branch=2025-05-01#1707256dd825f14e98161a49fdd6749f8ca0d506" +source = "git+https://github.com/servo/stylo?rev=refs%2Fpull%2F190%2Fhead#f63374493723974a6ec303f30a647ca22c3ae07b" dependencies = [ "darling", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index b24a468abd0..ee6272d915d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -119,7 +119,7 @@ rustls-pemfile = "2.0" rustls-pki-types = "1.12" script_layout_interface = { path = "components/shared/script_layout" } script_traits = { path = "components/shared/script" } -selectors = { git = "https://github.com/servo/stylo", branch = "2025-05-01" } +selectors = { git = "https://github.com/servo/stylo", rev = "refs/pull/190/head" } serde = "1.0.219" serde_bytes = "0.11" serde_json = "1.0" @@ -127,7 +127,7 @@ servo-media = { git = "https://github.com/servo/media" } servo-media-dummy = { git = "https://github.com/servo/media" } servo-media-gstreamer = { git = "https://github.com/servo/media" } servo-tracing = { path = "components/servo_tracing" } -servo_arc = { git = "https://github.com/servo/stylo", branch = "2025-05-01" } +servo_arc = { git = "https://github.com/servo/stylo", rev = "refs/pull/190/head" } smallbitvec = "2.6.0" smallvec = "1.15" snapshot = { path = "./components/shared/snapshot" } @@ -136,12 +136,12 @@ string_cache = "0.8" string_cache_codegen = "0.5" strum = "0.26" strum_macros = "0.26" -stylo = { git = "https://github.com/servo/stylo", branch = "2025-05-01" } -stylo_atoms = { git = "https://github.com/servo/stylo", branch = "2025-05-01" } -stylo_config = { git = "https://github.com/servo/stylo", branch = "2025-05-01" } -stylo_dom = { git = "https://github.com/servo/stylo", branch = "2025-05-01" } -stylo_malloc_size_of = { git = "https://github.com/servo/stylo", branch = "2025-05-01" } -stylo_traits = { git = "https://github.com/servo/stylo", branch = "2025-05-01" } +stylo = { git = "https://github.com/servo/stylo", rev = "refs/pull/190/head" } +stylo_atoms = { git = "https://github.com/servo/stylo", rev = "refs/pull/190/head" } +stylo_config = { git = "https://github.com/servo/stylo", rev = "refs/pull/190/head" } +stylo_dom = { git = "https://github.com/servo/stylo", rev = "refs/pull/190/head" } +stylo_malloc_size_of = { git = "https://github.com/servo/stylo", rev = "refs/pull/190/head" } +stylo_traits = { git = "https://github.com/servo/stylo", rev = "refs/pull/190/head" } surfman = { git = "https://github.com/servo/surfman", rev = "f7688b4585f9e0b5d4bf8ee8e4a91e82349610b1", features = ["chains"] } syn = { version = "2", default-features = false, features = ["clone-impls", "derive", "parsing"] } synstructure = "0.13" diff --git a/components/layout/display_list/stacking_context.rs b/components/layout/display_list/stacking_context.rs index 66d8421e5f7..61fcb9b8b9a 100644 --- a/components/layout/display_list/stacking_context.rs +++ b/components/layout/display_list/stacking_context.rs @@ -14,8 +14,8 @@ use compositing_traits::display_list::{ AxesScrollSensitivity, CompositorDisplayListInfo, ReferenceFrameNodeInfo, ScrollableNodeInfo, SpatialTreeNodeInfo, StickyNodeInfo, }; -use euclid::SideOffsets2D; use euclid::default::{Point2D, Rect, Size2D}; +use euclid::{SideOffsets2D, Vector2D}; use log::warn; use servo_config::opts::DebugOptions; use style::Zero; @@ -33,8 +33,7 @@ use style::values::generics::transform::{self, GenericRotate, GenericScale, Gene use style::values::specified::box_::DisplayOutside; use webrender_api::units::{LayoutPoint, LayoutRect, LayoutTransform, LayoutVector2D}; use webrender_api::{self as wr, BorderRadius}; -use wr::StickyOffsetBounds; -use wr::units::{LayoutPixel, LayoutSize}; +use wr::units::LayoutSize; use super::ClipId; use super::clip::StackingContextTreeClipStore; @@ -113,6 +112,10 @@ pub(crate) struct StackingContextTree { /// for things like `overflow`. More clips may be created later during WebRender /// display list construction, but they are never added here. pub clip_store: StackingContextTreeClipStore, + + /// A vector of `Fragment`s that created spatial nodes in the Compositor's + /// `ScrollTree`. This is used to patch up spatial nodes during repaint-only layouts. + pub fragments_creating_spatial_nodes: Vec>, } impl StackingContextTree { @@ -168,6 +171,10 @@ impl StackingContextTree { root_stacking_context: StackingContext::create_root(root_scroll_node_id, debug), compositor_info, clip_store: Default::default(), + // We are adding two empty slots here, because the Compositor `ScrollTree` + // adds two nodes for the root. These should never be patched during repaint + // only layouts. + fragments_creating_spatial_nodes: vec![None, None], }; let mut root_stacking_context = StackingContext::create_root(root_scroll_node_id, debug); @@ -192,62 +199,35 @@ impl StackingContextTree { stacking_context_tree } - fn push_reference_frame( - &mut self, - origin: LayoutPoint, - parent_scroll_node_id: &ScrollTreeNodeId, - transform_style: wr::TransformStyle, - transform: LayoutTransform, - kind: wr::ReferenceFrameKind, - ) -> ScrollTreeNodeId { - self.compositor_info.scroll_tree.add_scroll_tree_node( - Some(parent_scroll_node_id), - SpatialTreeNodeInfo::ReferenceFrame(ReferenceFrameNodeInfo { - origin, - transform_style, - transform, - kind, - }), - ) - } + pub(crate) fn repair_scroll_tree_for_repaint_only_layout(&mut self) { + for (fragment, node) in self + .fragments_creating_spatial_nodes + .iter() + .zip(self.compositor_info.scroll_tree.nodes.iter_mut()) + { + let box_fragment = match fragment { + Some(Fragment::Box(box_fragment) | Fragment::Float(box_fragment)) => box_fragment, + _ => continue, + }; - fn define_scroll_frame( - &mut self, - parent_scroll_node_id: &ScrollTreeNodeId, - external_id: wr::ExternalScrollId, - content_rect: LayoutRect, - clip_rect: LayoutRect, - scroll_sensitivity: AxesScrollSensitivity, - ) -> ScrollTreeNodeId { - self.compositor_info.scroll_tree.add_scroll_tree_node( - Some(parent_scroll_node_id), - SpatialTreeNodeInfo::Scroll(ScrollableNodeInfo { - external_id, - content_rect, - clip_rect, - scroll_sensitivity, - offset: LayoutVector2D::zero(), - }), - ) - } + let SpatialTreeNodeInfo::ReferenceFrame(ref mut info) = node.info else { + continue; + }; - fn define_sticky_frame( - &mut self, - parent_scroll_node_id: &ScrollTreeNodeId, - frame_rect: LayoutRect, - margins: SideOffsets2D, LayoutPixel>, - vertical_offset_bounds: StickyOffsetBounds, - horizontal_offset_bounds: StickyOffsetBounds, - ) -> ScrollTreeNodeId { - self.compositor_info.scroll_tree.add_scroll_tree_node( - Some(parent_scroll_node_id), - SpatialTreeNodeInfo::Sticky(StickyNodeInfo { - frame_rect, - margins, - vertical_offset_bounds, - horizontal_offset_bounds, - }), - ) + // The argument to `reference_frame_node_info_if_necessary` here is only used to calculate the + // reference frame origin. If the origin changes, we will not be doing a repaint only layout, + // and thus it's not necessary to pass a real value. + let box_fragment = box_fragment.borrow(); + let Some(reference_frame_data) = + box_fragment.reference_frame_node_info_if_necessary(&PhysicalRect::zero()) + else { + return; + }; + + info.kind = reference_frame_data.kind; + info.transform = reference_frame_data.transform; + info.transform_style = reference_frame_data.transform_style; + } } } @@ -889,11 +869,6 @@ impl Fragment { } } -struct ReferenceFrameData { - origin: crate::geom::PhysicalPoint, - transform: LayoutTransform, - kind: wr::ReferenceFrameKind, -} struct ScrollFrameData { scroll_tree_node_id: ScrollTreeNodeId, scroll_frame_rect: LayoutRect, @@ -966,8 +941,8 @@ impl BoxFragment { parent_stacking_context: &mut StackingContext, text_decorations: &Arc>, ) { - let reference_frame_data = - match self.reference_frame_data_if_necessary(&containing_block.rect) { + let reference_frame_node_info = + match self.reference_frame_node_info_if_necessary(&containing_block.rect) { Some(reference_frame_data) => reference_frame_data, None => { return self.build_stacking_context_tree_maybe_creating_stacking_context( @@ -984,17 +959,24 @@ impl BoxFragment { // // > 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. - if !reference_frame_data.transform.is_invertible() { + if !reference_frame_node_info.transform.is_invertible() { return; } - let new_spatial_id = stacking_context_tree.push_reference_frame( - reference_frame_data.origin.to_webrender(), - &containing_block.scroll_node_id, - self.style.get_box().transform_style.to_webrender(), - reference_frame_data.transform, - reference_frame_data.kind, + let reference_frame_origin = Vector2D::new( + Au::from_f32_px(reference_frame_node_info.origin.x), + Au::from_f32_px(reference_frame_node_info.origin.y), ); + let new_spatial_id = stacking_context_tree + .compositor_info + .scroll_tree + .add_scroll_tree_node( + Some(&containing_block.scroll_node_id), + SpatialTreeNodeInfo::ReferenceFrame(reference_frame_node_info), + ); + stacking_context_tree + .fragments_creating_spatial_nodes + .push(Some(fragment.clone())); // WebRender reference frames establish a new coordinate system at their // origin (the border box of the fragment). We need to ensure that any @@ -1009,10 +991,9 @@ impl BoxFragment { self.style .establishes_containing_block_for_all_descendants(self.base.flags) ); + let adjusted_containing_block = ContainingBlock::new( - containing_block - .rect - .translate(-reference_frame_data.origin.to_vector()), + containing_block.rect.translate(-reference_frame_origin), new_spatial_id, None, containing_block.clip_id, @@ -1137,6 +1118,7 @@ impl BoxFragment { .scroll_frame_size; if let Some(scroll_node_id) = self.build_sticky_frame_if_necessary( + &fragment, stacking_context_tree, &new_scroll_node_id, &containing_block.rect, @@ -1209,6 +1191,7 @@ impl BoxFragment { // We want to build the scroll frame after the background and border, because // they shouldn't scroll with the rest of the box content. if let Some(overflow_frame_data) = self.build_overflow_frame_if_necessary( + &fragment, stacking_context_tree, &new_scroll_node_id, new_clip_id, @@ -1371,6 +1354,7 @@ impl BoxFragment { fn build_overflow_frame_if_necessary( &self, + fragment: &Fragment, stacking_context_tree: &mut StackingContextTree, parent_scroll_node_id: &ScrollTreeNodeId, parent_clip_id: ClipId, @@ -1463,20 +1447,28 @@ impl BoxFragment { stacking_context_tree.compositor_info.pipeline_id, ); - let sensitivity = AxesScrollSensitivity { + let scroll_sensitivity = AxesScrollSensitivity { x: overflow.x.into(), y: overflow.y.into(), }; let content_rect = self.reachable_scrollable_overflow_region().to_webrender(); - - let scroll_tree_node_id = stacking_context_tree.define_scroll_frame( - parent_scroll_node_id, - external_id, - content_rect, - scroll_frame_rect, - sensitivity, - ); + let scroll_tree_node_id = stacking_context_tree + .compositor_info + .scroll_tree + .add_scroll_tree_node( + Some(parent_scroll_node_id), + SpatialTreeNodeInfo::Scroll(ScrollableNodeInfo { + external_id, + content_rect, + clip_rect: scroll_frame_rect, + scroll_sensitivity, + offset: LayoutVector2D::zero(), + }), + ); + stacking_context_tree + .fragments_creating_spatial_nodes + .push(Some(fragment.clone())); Some(OverflowFrameData { clip_id, @@ -1489,6 +1481,7 @@ impl BoxFragment { fn build_sticky_frame_if_necessary( &self, + fragment: &Fragment, stacking_context_tree: &mut StackingContextTree, parent_scroll_node_id: &ScrollTreeNodeId, containing_block_rect: &PhysicalRect, @@ -1559,22 +1552,30 @@ impl BoxFragment { offsets.left.non_auto().map(|v| v.to_f32_px()), ); - let sticky_node_id = stacking_context_tree.define_sticky_frame( - parent_scroll_node_id, - frame_rect, - margins, - vertical_offset_bounds, - horizontal_offset_bounds, - ); + let sticky_node_id = stacking_context_tree + .compositor_info + .scroll_tree + .add_scroll_tree_node( + Some(parent_scroll_node_id), + SpatialTreeNodeInfo::Sticky(StickyNodeInfo { + frame_rect, + margins, + vertical_offset_bounds, + horizontal_offset_bounds, + }), + ); + stacking_context_tree + .fragments_creating_spatial_nodes + .push(Some(fragment.clone())); Some(sticky_node_id) } /// Optionally returns the data for building a reference frame, without yet building it. - fn reference_frame_data_if_necessary( + fn reference_frame_node_info_if_necessary( &self, containing_block_rect: &PhysicalRect, - ) -> Option { + ) -> Option { if !self .style .has_effective_transform_or_perspective(self.base.flags) @@ -1612,9 +1613,10 @@ impl BoxFragment { (None, None) => unreachable!(), }; - Some(ReferenceFrameData { - origin: border_rect.origin, + Some(ReferenceFrameNodeInfo { + origin: border_rect.origin.to_webrender(), transform: reference_frame_transform, + transform_style: self.style.get_box().transform_style.to_webrender(), kind: reference_frame_kind, }) } diff --git a/components/layout/layout_impl.rs b/components/layout/layout_impl.rs index 54edc215389..7cc53320de6 100644 --- a/components/layout/layout_impl.rs +++ b/components/layout/layout_impl.rs @@ -846,10 +846,12 @@ impl LayoutThread { let Some(fragment_tree) = &*self.fragment_tree.borrow() else { return; }; - if !damage.contains(RestyleDamage::REBUILD_STACKING_CONTEXT) && - self.stacking_context_tree.borrow().is_some() - { - return; + + if !damage.contains(RestyleDamage::REBUILD_STACKING_CONTEXT) { + if let Some(stacking_context_tree) = &mut *self.stacking_context_tree.borrow_mut() { + stacking_context_tree.repair_scroll_tree_for_repaint_only_layout(); + return; + } } let viewport_size = self.stylist.device().au_viewport_size();