diff --git a/components/layout/layout_impl.rs b/components/layout/layout_impl.rs index e95fe213b43..66683738317 100644 --- a/components/layout/layout_impl.rs +++ b/components/layout/layout_impl.rs @@ -27,7 +27,7 @@ use fxhash::FxHashMap; use ipc_channel::ipc::IpcSender; use layout_api::{ Layout, LayoutConfig, LayoutFactory, NodesFromPointQueryType, OffsetParentResponse, QueryMsg, - ReflowGoal, ReflowRequest, ReflowResult, TrustedNodeAddress, + ReflowGoal, ReflowRequest, ReflowRequestRestyle, ReflowResult, TrustedNodeAddress, }; use log::{debug, error, warn}; use malloc_size_of::{MallocConditionalSizeOf, MallocSizeOf, MallocSizeOfOps}; @@ -586,7 +586,7 @@ impl LayoutThread { /// at all. fn can_skip_reflow_request_entirely(&self, reflow_request: &ReflowRequest) -> bool { // If a restyle is necessary, restyle and reflow is a necessity. - if reflow_request.restyle_reason.needs_restyle() { + if reflow_request.restyle.is_some() { return false; } // We always need to at least build a fragment tree. @@ -649,9 +649,11 @@ impl LayoutThread { }; let mut snapshot_map = SnapshotMap::new(); - let _snapshot_setter = SnapshotSetter::new(&mut reflow_request, &mut snapshot_map); + let mut _snapshot_setter = None; let mut viewport_changed = false; - if reflow_request.restyle_reason.needs_restyle() { + if let Some(restyle) = reflow_request.restyle.as_mut() { + _snapshot_setter = Some(SnapshotSetter::new(restyle, &mut snapshot_map)); + viewport_changed = self.viewport_did_change(reflow_request.viewport_details); if self.update_device_if_necessary(&reflow_request, viewport_changed, &guards) { if let Some(mut data) = root_element.mutate_data() { @@ -683,7 +685,7 @@ impl LayoutThread { &snapshot_map, reflow_request.animation_timeline_value, &reflow_request.animations, - match reflow_request.stylesheets_changed { + match reflow_request.stylesheets_changed() { true => TraversalFlags::ForCSSRuleChanges, false => TraversalFlags::empty(), }, @@ -700,9 +702,9 @@ impl LayoutThread { }; let mut damage = RestyleDamage::empty(); - if reflow_request.restyle_reason.needs_restyle() { + if let Some(restyle) = reflow_request.restyle.as_ref() { damage = self.restyle_and_build_trees( - &reflow_request, + restyle, root_element, rayon_pool, &mut layout_context, @@ -794,7 +796,7 @@ impl LayoutThread { self.have_added_user_agent_stylesheets = true; } - if reflow_request.stylesheets_changed { + if reflow_request.stylesheets_changed() { self.stylist .force_stylesheet_origins_dirty(Origin::Author.into()); } @@ -809,14 +811,14 @@ impl LayoutThread { #[servo_tracing::instrument(skip_all)] fn restyle_and_build_trees( &self, - reflow_request: &ReflowRequest, + restyle: &ReflowRequestRestyle, root_element: ServoLayoutElement<'_>, rayon_pool: Option<&ThreadPool>, layout_context: &mut LayoutContext<'_>, viewport_changed: bool, ) -> RestyleDamage { let dirty_root = unsafe { - ServoLayoutNode::new(&reflow_request.dirty_root.unwrap()) + ServoLayoutNode::new(&restyle.dirty_root.unwrap()) .as_element() .unwrap() }; @@ -1330,12 +1332,9 @@ struct SnapshotSetter<'dom> { } impl SnapshotSetter<'_> { - fn new(reflow_request: &mut ReflowRequest, snapshot_map: &mut SnapshotMap) -> Self { - debug!( - "Draining restyles: {}", - reflow_request.pending_restyles.len() - ); - let restyles = std::mem::take(&mut reflow_request.pending_restyles); + fn new(restyle: &mut ReflowRequestRestyle, snapshot_map: &mut SnapshotMap) -> Self { + debug!("Draining restyles: {}", restyle.pending_restyles.len()); + let restyles = std::mem::take(&mut restyle.pending_restyles); let elements_with_snapshot: Vec<_> = restyles .iter() diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 578d894f912..fbb03f1b764 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -52,8 +52,8 @@ use js::rust::{ MutableHandleValue, }; use layout_api::{ - FragmentType, Layout, PendingImageState, QueryMsg, ReflowGoal, ReflowRequest, RestyleReason, - TrustedNodeAddress, combine_id_with_fragment_type, + FragmentType, Layout, PendingImageState, QueryMsg, ReflowGoal, ReflowRequest, + ReflowRequestRestyle, RestyleReason, TrustedNodeAddress, combine_id_with_fragment_type, }; use malloc_size_of::MallocSizeOf; use media::WindowGLContext; @@ -2143,17 +2143,6 @@ impl Window { return false; } - let restyle_reason = document.restyle_reason(); - document.clear_restyle_reasons(); - - if restyle_reason.needs_restyle() { - debug!("Invalidating layout cache due to reflow condition {restyle_reason:?}",); - // Invalidate any existing cached layout values. - self.layout_marker.borrow().set(false); - // Create a new layout caching token. - *self.layout_marker.borrow_mut() = Rc::new(Cell::new(true)); - } - debug!("script: performing reflow for goal {reflow_goal:?}"); let marker = if self.need_emit_timeline_marker(TimelineMarkerType::Reflow) { Some(TimelineMarker::start("Reflow".to_owned())) @@ -2166,27 +2155,43 @@ impl Window { debug_reflow_events(pipeline_id, &reflow_goal); } - let stylesheets_changed = document.flush_stylesheets_for_reflow(); - let pending_restyles = document.drain_pending_restyles(); - let dirty_root = document - .take_dirty_root() - .filter(|_| !stylesheets_changed) - .or_else(|| document.GetDocumentElement()) - .map(|root| root.upcast::().to_trusted_node_address()); + let restyle_reason = document.restyle_reason(); + document.clear_restyle_reasons(); + let restyle = if restyle_reason.needs_restyle() { + debug!("Invalidating layout cache due to reflow condition {restyle_reason:?}",); + // Invalidate any existing cached layout values. + self.layout_marker.borrow().set(false); + // Create a new layout caching token. + *self.layout_marker.borrow_mut() = Rc::new(Cell::new(true)); + + let stylesheets_changed = document.flush_stylesheets_for_reflow(); + let pending_restyles = document.drain_pending_restyles(); + let dirty_root = document + .take_dirty_root() + .filter(|_| !stylesheets_changed) + .or_else(|| document.GetDocumentElement()) + .map(|root| root.upcast::().to_trusted_node_address()); + + Some(ReflowRequestRestyle { + reason: restyle_reason, + dirty_root, + stylesheets_changed, + pending_restyles, + }) + } else { + None + }; let highlighted_dom_node = document.highlighted_dom_node().map(|node| node.to_opaque()); // Send new document and relevant styles to layout. let reflow = ReflowRequest { - restyle_reason, document: document.upcast::().to_trusted_node_address(), - dirty_root, - stylesheets_changed, + restyle, viewport_details: self.viewport_details.get(), origin: self.origin().immutable().clone(), reflow_goal, dom_count: document.dom_count(), - pending_restyles, animation_timeline_value: document.current_animation_timeline_value(), animations: document.animations().sets.clone(), node_to_animating_image_map: document.image_animation_manager().node_to_image_map(), diff --git a/components/shared/layout/lib.rs b/components/shared/layout/lib.rs index 8b1f6009dee..36d6373f797 100644 --- a/components/shared/layout/lib.rs +++ b/components/shared/layout/lib.rs @@ -395,17 +395,27 @@ pub struct ReflowResult { pub iframe_sizes: IFrameSizes, } -/// Information needed for a script-initiated reflow. +/// Information needed for a script-initiated reflow that requires a restyle +/// and reconstruction of box and fragment trees. #[derive(Debug)] -pub struct ReflowRequest { +pub struct ReflowRequestRestyle { /// Whether or not (and for what reasons) restyle needs to happen. - pub restyle_reason: RestyleReason, - /// The document node. - pub document: TrustedNodeAddress, + pub reason: RestyleReason, /// The dirty root from which to restyle. pub dirty_root: Option, /// Whether the document's stylesheets have changed since the last script reflow. pub stylesheets_changed: bool, + /// Restyle snapshot map. + pub pending_restyles: Vec<(TrustedNodeAddress, PendingRestyle)>, +} + +/// Information needed for a script-initiated reflow. +#[derive(Debug)] +pub struct ReflowRequest { + /// The document node. + pub document: TrustedNodeAddress, + /// If a restyle is necessary, all of the informatio needed to do that restyle. + pub restyle: Option, /// The current [`ViewportDetails`] to use for this reflow. pub viewport_details: ViewportDetails, /// The goal of this reflow. @@ -414,8 +424,6 @@ pub struct ReflowRequest { pub dom_count: u32, /// The current window origin pub origin: ImmutableOrigin, - /// Restyle snapshot map. - pub pending_restyles: Vec<(TrustedNodeAddress, PendingRestyle)>, /// The current animation timeline value. pub animation_timeline_value: f64, /// The set of animations for this document. @@ -428,6 +436,14 @@ pub struct ReflowRequest { pub highlighted_dom_node: Option, } +impl ReflowRequest { + pub fn stylesheets_changed(&self) -> bool { + self.restyle + .as_ref() + .is_some_and(|restyle| restyle.stylesheets_changed) + } +} + /// A pending restyle. #[derive(Debug, Default, MallocSizeOf)] pub struct PendingRestyle {