mirror of
https://github.com/servo/servo.git
synced 2025-07-08 07:53:40 +01:00
layout: Do not require restyle information when not restyling (#37722)
This reduces the amount of work necessary when running layout, by making restyle information optional in the `ReflowRequest`. When restyling isn't necessary, the option is `None`. Testing: This shouldn't change any observable behavior and thus is covered by existing WPT tests. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
cbb0407ae6
commit
8e2ef5c248
3 changed files with 67 additions and 47 deletions
|
@ -27,7 +27,7 @@ use fxhash::FxHashMap;
|
||||||
use ipc_channel::ipc::IpcSender;
|
use ipc_channel::ipc::IpcSender;
|
||||||
use layout_api::{
|
use layout_api::{
|
||||||
Layout, LayoutConfig, LayoutFactory, NodesFromPointQueryType, OffsetParentResponse, QueryMsg,
|
Layout, LayoutConfig, LayoutFactory, NodesFromPointQueryType, OffsetParentResponse, QueryMsg,
|
||||||
ReflowGoal, ReflowRequest, ReflowResult, TrustedNodeAddress,
|
ReflowGoal, ReflowRequest, ReflowRequestRestyle, ReflowResult, TrustedNodeAddress,
|
||||||
};
|
};
|
||||||
use log::{debug, error, warn};
|
use log::{debug, error, warn};
|
||||||
use malloc_size_of::{MallocConditionalSizeOf, MallocSizeOf, MallocSizeOfOps};
|
use malloc_size_of::{MallocConditionalSizeOf, MallocSizeOf, MallocSizeOfOps};
|
||||||
|
@ -586,7 +586,7 @@ impl LayoutThread {
|
||||||
/// at all.
|
/// at all.
|
||||||
fn can_skip_reflow_request_entirely(&self, reflow_request: &ReflowRequest) -> bool {
|
fn can_skip_reflow_request_entirely(&self, reflow_request: &ReflowRequest) -> bool {
|
||||||
// If a restyle is necessary, restyle and reflow is a necessity.
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
// We always need to at least build a fragment tree.
|
// We always need to at least build a fragment tree.
|
||||||
|
@ -649,9 +649,11 @@ impl LayoutThread {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut snapshot_map = SnapshotMap::new();
|
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;
|
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);
|
viewport_changed = self.viewport_did_change(reflow_request.viewport_details);
|
||||||
if self.update_device_if_necessary(&reflow_request, viewport_changed, &guards) {
|
if self.update_device_if_necessary(&reflow_request, viewport_changed, &guards) {
|
||||||
if let Some(mut data) = root_element.mutate_data() {
|
if let Some(mut data) = root_element.mutate_data() {
|
||||||
|
@ -683,7 +685,7 @@ impl LayoutThread {
|
||||||
&snapshot_map,
|
&snapshot_map,
|
||||||
reflow_request.animation_timeline_value,
|
reflow_request.animation_timeline_value,
|
||||||
&reflow_request.animations,
|
&reflow_request.animations,
|
||||||
match reflow_request.stylesheets_changed {
|
match reflow_request.stylesheets_changed() {
|
||||||
true => TraversalFlags::ForCSSRuleChanges,
|
true => TraversalFlags::ForCSSRuleChanges,
|
||||||
false => TraversalFlags::empty(),
|
false => TraversalFlags::empty(),
|
||||||
},
|
},
|
||||||
|
@ -700,9 +702,9 @@ impl LayoutThread {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut damage = RestyleDamage::empty();
|
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(
|
damage = self.restyle_and_build_trees(
|
||||||
&reflow_request,
|
restyle,
|
||||||
root_element,
|
root_element,
|
||||||
rayon_pool,
|
rayon_pool,
|
||||||
&mut layout_context,
|
&mut layout_context,
|
||||||
|
@ -794,7 +796,7 @@ impl LayoutThread {
|
||||||
self.have_added_user_agent_stylesheets = true;
|
self.have_added_user_agent_stylesheets = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if reflow_request.stylesheets_changed {
|
if reflow_request.stylesheets_changed() {
|
||||||
self.stylist
|
self.stylist
|
||||||
.force_stylesheet_origins_dirty(Origin::Author.into());
|
.force_stylesheet_origins_dirty(Origin::Author.into());
|
||||||
}
|
}
|
||||||
|
@ -809,14 +811,14 @@ impl LayoutThread {
|
||||||
#[servo_tracing::instrument(skip_all)]
|
#[servo_tracing::instrument(skip_all)]
|
||||||
fn restyle_and_build_trees(
|
fn restyle_and_build_trees(
|
||||||
&self,
|
&self,
|
||||||
reflow_request: &ReflowRequest,
|
restyle: &ReflowRequestRestyle,
|
||||||
root_element: ServoLayoutElement<'_>,
|
root_element: ServoLayoutElement<'_>,
|
||||||
rayon_pool: Option<&ThreadPool>,
|
rayon_pool: Option<&ThreadPool>,
|
||||||
layout_context: &mut LayoutContext<'_>,
|
layout_context: &mut LayoutContext<'_>,
|
||||||
viewport_changed: bool,
|
viewport_changed: bool,
|
||||||
) -> RestyleDamage {
|
) -> RestyleDamage {
|
||||||
let dirty_root = unsafe {
|
let dirty_root = unsafe {
|
||||||
ServoLayoutNode::new(&reflow_request.dirty_root.unwrap())
|
ServoLayoutNode::new(&restyle.dirty_root.unwrap())
|
||||||
.as_element()
|
.as_element()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
@ -1330,12 +1332,9 @@ struct SnapshotSetter<'dom> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SnapshotSetter<'_> {
|
impl SnapshotSetter<'_> {
|
||||||
fn new(reflow_request: &mut ReflowRequest, snapshot_map: &mut SnapshotMap) -> Self {
|
fn new(restyle: &mut ReflowRequestRestyle, snapshot_map: &mut SnapshotMap) -> Self {
|
||||||
debug!(
|
debug!("Draining restyles: {}", restyle.pending_restyles.len());
|
||||||
"Draining restyles: {}",
|
let restyles = std::mem::take(&mut restyle.pending_restyles);
|
||||||
reflow_request.pending_restyles.len()
|
|
||||||
);
|
|
||||||
let restyles = std::mem::take(&mut reflow_request.pending_restyles);
|
|
||||||
|
|
||||||
let elements_with_snapshot: Vec<_> = restyles
|
let elements_with_snapshot: Vec<_> = restyles
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -52,8 +52,8 @@ use js::rust::{
|
||||||
MutableHandleValue,
|
MutableHandleValue,
|
||||||
};
|
};
|
||||||
use layout_api::{
|
use layout_api::{
|
||||||
FragmentType, Layout, PendingImageState, QueryMsg, ReflowGoal, ReflowRequest, RestyleReason,
|
FragmentType, Layout, PendingImageState, QueryMsg, ReflowGoal, ReflowRequest,
|
||||||
TrustedNodeAddress, combine_id_with_fragment_type,
|
ReflowRequestRestyle, RestyleReason, TrustedNodeAddress, combine_id_with_fragment_type,
|
||||||
};
|
};
|
||||||
use malloc_size_of::MallocSizeOf;
|
use malloc_size_of::MallocSizeOf;
|
||||||
use media::WindowGLContext;
|
use media::WindowGLContext;
|
||||||
|
@ -2143,17 +2143,6 @@ impl Window {
|
||||||
return false;
|
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:?}");
|
debug!("script: performing reflow for goal {reflow_goal:?}");
|
||||||
let marker = if self.need_emit_timeline_marker(TimelineMarkerType::Reflow) {
|
let marker = if self.need_emit_timeline_marker(TimelineMarkerType::Reflow) {
|
||||||
Some(TimelineMarker::start("Reflow".to_owned()))
|
Some(TimelineMarker::start("Reflow".to_owned()))
|
||||||
|
@ -2166,6 +2155,15 @@ impl Window {
|
||||||
debug_reflow_events(pipeline_id, &reflow_goal);
|
debug_reflow_events(pipeline_id, &reflow_goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 stylesheets_changed = document.flush_stylesheets_for_reflow();
|
||||||
let pending_restyles = document.drain_pending_restyles();
|
let pending_restyles = document.drain_pending_restyles();
|
||||||
let dirty_root = document
|
let dirty_root = document
|
||||||
|
@ -2174,19 +2172,26 @@ impl Window {
|
||||||
.or_else(|| document.GetDocumentElement())
|
.or_else(|| document.GetDocumentElement())
|
||||||
.map(|root| root.upcast::<Node>().to_trusted_node_address());
|
.map(|root| root.upcast::<Node>().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());
|
let highlighted_dom_node = document.highlighted_dom_node().map(|node| node.to_opaque());
|
||||||
|
|
||||||
// Send new document and relevant styles to layout.
|
// Send new document and relevant styles to layout.
|
||||||
let reflow = ReflowRequest {
|
let reflow = ReflowRequest {
|
||||||
restyle_reason,
|
|
||||||
document: document.upcast::<Node>().to_trusted_node_address(),
|
document: document.upcast::<Node>().to_trusted_node_address(),
|
||||||
dirty_root,
|
restyle,
|
||||||
stylesheets_changed,
|
|
||||||
viewport_details: self.viewport_details.get(),
|
viewport_details: self.viewport_details.get(),
|
||||||
origin: self.origin().immutable().clone(),
|
origin: self.origin().immutable().clone(),
|
||||||
reflow_goal,
|
reflow_goal,
|
||||||
dom_count: document.dom_count(),
|
dom_count: document.dom_count(),
|
||||||
pending_restyles,
|
|
||||||
animation_timeline_value: document.current_animation_timeline_value(),
|
animation_timeline_value: document.current_animation_timeline_value(),
|
||||||
animations: document.animations().sets.clone(),
|
animations: document.animations().sets.clone(),
|
||||||
node_to_animating_image_map: document.image_animation_manager().node_to_image_map(),
|
node_to_animating_image_map: document.image_animation_manager().node_to_image_map(),
|
||||||
|
|
|
@ -395,17 +395,27 @@ pub struct ReflowResult {
|
||||||
pub iframe_sizes: IFrameSizes,
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct ReflowRequest {
|
pub struct ReflowRequestRestyle {
|
||||||
/// Whether or not (and for what reasons) restyle needs to happen.
|
/// Whether or not (and for what reasons) restyle needs to happen.
|
||||||
pub restyle_reason: RestyleReason,
|
pub reason: RestyleReason,
|
||||||
/// The document node.
|
|
||||||
pub document: TrustedNodeAddress,
|
|
||||||
/// The dirty root from which to restyle.
|
/// The dirty root from which to restyle.
|
||||||
pub dirty_root: Option<TrustedNodeAddress>,
|
pub dirty_root: Option<TrustedNodeAddress>,
|
||||||
/// Whether the document's stylesheets have changed since the last script reflow.
|
/// Whether the document's stylesheets have changed since the last script reflow.
|
||||||
pub stylesheets_changed: bool,
|
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<ReflowRequestRestyle>,
|
||||||
/// The current [`ViewportDetails`] to use for this reflow.
|
/// The current [`ViewportDetails`] to use for this reflow.
|
||||||
pub viewport_details: ViewportDetails,
|
pub viewport_details: ViewportDetails,
|
||||||
/// The goal of this reflow.
|
/// The goal of this reflow.
|
||||||
|
@ -414,8 +424,6 @@ pub struct ReflowRequest {
|
||||||
pub dom_count: u32,
|
pub dom_count: u32,
|
||||||
/// The current window origin
|
/// The current window origin
|
||||||
pub origin: ImmutableOrigin,
|
pub origin: ImmutableOrigin,
|
||||||
/// Restyle snapshot map.
|
|
||||||
pub pending_restyles: Vec<(TrustedNodeAddress, PendingRestyle)>,
|
|
||||||
/// The current animation timeline value.
|
/// The current animation timeline value.
|
||||||
pub animation_timeline_value: f64,
|
pub animation_timeline_value: f64,
|
||||||
/// The set of animations for this document.
|
/// The set of animations for this document.
|
||||||
|
@ -428,6 +436,14 @@ pub struct ReflowRequest {
|
||||||
pub highlighted_dom_node: Option<OpaqueNode>,
|
pub highlighted_dom_node: Option<OpaqueNode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ReflowRequest {
|
||||||
|
pub fn stylesheets_changed(&self) -> bool {
|
||||||
|
self.restyle
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|restyle| restyle.stylesheets_changed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A pending restyle.
|
/// A pending restyle.
|
||||||
#[derive(Debug, Default, MallocSizeOf)]
|
#[derive(Debug, Default, MallocSizeOf)]
|
||||||
pub struct PendingRestyle {
|
pub struct PendingRestyle {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue