Update new scroll tree offset based on the old one

Signed-off-by: stevennovaryo <steven.novaryo@gmail.com>
This commit is contained in:
stevennovaryo 2025-06-04 21:24:29 +08:00
parent 25b27b2040
commit 76405114f6
6 changed files with 132 additions and 42 deletions

View file

@ -257,7 +257,7 @@ impl PipelineDetails {
} }
} }
// MYNOTES: move this to display list // MYNOTES: we also do this in the display list now
fn install_new_scroll_tree(&mut self, new_scroll_tree: ScrollTree) { fn install_new_scroll_tree(&mut self, new_scroll_tree: ScrollTree) {
let old_scroll_offsets: FnvHashMap<ExternalScrollId, LayoutVector2D> = self let old_scroll_offsets: FnvHashMap<ExternalScrollId, LayoutVector2D> = self
.scroll_tree .scroll_tree
@ -731,7 +731,10 @@ impl IOCompositor {
if !pipeline_details if !pipeline_details
.scroll_tree .scroll_tree
.set_scroll_offsets_for_node_with_external_scroll_id(&external_scroll_id, offset) .set_scroll_offsets_for_node_with_external_scroll_id(
&external_scroll_id,
offset,
)
{ {
warn!("Could not scroll not with id: {external_scroll_id:?}"); warn!("Could not scroll not with id: {external_scroll_id:?}");
return; return;

View file

@ -862,9 +862,10 @@ impl WebViewRenderer {
combined_event.scroll_location, combined_event.scroll_location,
) )
}); });
if let Some(scroll_result) = scroll_result { // MYNOTES: change this to single update
self.send_scroll_positions_to_layout_for_pipeline(scroll_result.pipeline_id); // if let Some(scroll_result) = scroll_result {
} // self.send_scroll_positions_to_layout_for_pipeline(scroll_result.pipeline_id);
// }
let pinch_zoom_result = match self let pinch_zoom_result = match self
.set_pinch_zoom_level(self.pinch_zoom_level().get() * combined_magnification) .set_pinch_zoom_level(self.pinch_zoom_level().get() * combined_magnification)

View file

@ -118,6 +118,8 @@ pub(crate) struct StackingContextTree {
impl StackingContextTree { impl StackingContextTree {
/// Create a new [DisplayList] given the dimensions of the layout and the WebRender /// Create a new [DisplayList] given the dimensions of the layout and the WebRender
/// pipeline id. /// pipeline id.
// MYNOTES: fix this
#[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
fragment_tree: &FragmentTree, fragment_tree: &FragmentTree,
viewport_size: LayoutSize, viewport_size: LayoutSize,
@ -126,6 +128,7 @@ impl StackingContextTree {
viewport_scroll_sensitivity: AxesScrollSensitivity, viewport_scroll_sensitivity: AxesScrollSensitivity,
first_reflow: bool, first_reflow: bool,
debug: &DebugOptions, debug: &DebugOptions,
maybe_old_stacking_context_tree: &Option<Box<StackingContextTree>>,
) -> Self { ) -> Self {
let compositor_info = CompositorDisplayListInfo::new( let compositor_info = CompositorDisplayListInfo::new(
viewport_size, viewport_size,
@ -179,6 +182,7 @@ impl StackingContextTree {
&mut root_stacking_context, &mut root_stacking_context,
StackingContextBuildMode::SkipHoisted, StackingContextBuildMode::SkipHoisted,
&text_decorations, &text_decorations,
maybe_old_stacking_context_tree,
); );
} }
root_stacking_context.sort(); root_stacking_context.sort();
@ -211,7 +215,7 @@ impl StackingContextTree {
) )
} }
fn define_scroll_frame( fn define_scroll_frame_with_zero_offset(
&mut self, &mut self,
parent_scroll_node_id: &ScrollTreeNodeId, parent_scroll_node_id: &ScrollTreeNodeId,
external_id: wr::ExternalScrollId, external_id: wr::ExternalScrollId,
@ -231,6 +235,39 @@ impl StackingContextTree {
) )
} }
/// Define a new scroll frame, but we are considering the old offset
/// from the previous scroll tree.
fn define_scroll_frame(
&mut self,
parent_scroll_node_id: &ScrollTreeNodeId,
external_id: wr::ExternalScrollId,
content_rect: LayoutRect,
clip_rect: LayoutRect,
scroll_sensitivity: AxesScrollSensitivity,
maybe_old_stacking_context_tree: &Option<Box<StackingContextTree>>,
) -> ScrollTreeNodeId {
let scroll_id = self.define_scroll_frame_with_zero_offset(
parent_scroll_node_id,
external_id,
content_rect,
clip_rect,
scroll_sensitivity,
);
if let Some(old_stacking_context_tree) = maybe_old_stacking_context_tree.as_ref() {
if let Some(old_scroll_node) = old_stacking_context_tree
.compositor_info
.scroll_tree
.get_node_by_external_scroll_id(&external_id)
{
self.compositor_info
.scroll_tree
.get_node_mut(&scroll_id)
.set_offset(old_scroll_node.offset().unwrap());
}
}
scroll_id
}
fn define_sticky_frame( fn define_sticky_frame(
&mut self, &mut self,
parent_scroll_node_id: &ScrollTreeNodeId, parent_scroll_node_id: &ScrollTreeNodeId,
@ -817,6 +854,7 @@ impl Fragment {
stacking_context: &mut StackingContext, stacking_context: &mut StackingContext,
mode: StackingContextBuildMode, mode: StackingContextBuildMode,
text_decorations: &Arc<Vec<FragmentTextDecoration>>, text_decorations: &Arc<Vec<FragmentTextDecoration>>,
maybe_old_stacking_context_tree: &Option<Box<StackingContextTree>>,
) { ) {
let containing_block = containing_block_info.get_containing_block_for_fragment(self); let containing_block = containing_block_info.get_containing_block_for_fragment(self);
let fragment_clone = self.clone(); let fragment_clone = self.clone();
@ -841,6 +879,7 @@ impl Fragment {
containing_block_info, containing_block_info,
stacking_context, stacking_context,
text_decorations, text_decorations,
maybe_old_stacking_context_tree,
); );
}, },
Fragment::AbsoluteOrFixedPositioned(fragment) => { Fragment::AbsoluteOrFixedPositioned(fragment) => {
@ -856,6 +895,7 @@ impl Fragment {
stacking_context, stacking_context,
StackingContextBuildMode::IncludeHoisted, StackingContextBuildMode::IncludeHoisted,
&Default::default(), &Default::default(),
maybe_old_stacking_context_tree,
); );
}, },
Fragment::Positioning(fragment) => { Fragment::Positioning(fragment) => {
@ -866,6 +906,7 @@ impl Fragment {
containing_block_info, containing_block_info,
stacking_context, stacking_context,
text_decorations, text_decorations,
maybe_old_stacking_context_tree,
); );
}, },
Fragment::Text(_) | Fragment::Image(_) | Fragment::IFrame(_) => { Fragment::Text(_) | Fragment::Image(_) | Fragment::IFrame(_) => {
@ -946,6 +987,7 @@ impl BoxFragment {
containing_block_info: &ContainingBlockInfo, containing_block_info: &ContainingBlockInfo,
parent_stacking_context: &mut StackingContext, parent_stacking_context: &mut StackingContext,
text_decorations: &Arc<Vec<FragmentTextDecoration>>, text_decorations: &Arc<Vec<FragmentTextDecoration>>,
maybe_old_stacking_context_tree: &Option<Box<StackingContextTree>>,
) { ) {
self.build_stacking_context_tree_maybe_creating_reference_frame( self.build_stacking_context_tree_maybe_creating_reference_frame(
fragment, fragment,
@ -954,6 +996,7 @@ impl BoxFragment {
containing_block_info, containing_block_info,
parent_stacking_context, parent_stacking_context,
text_decorations, text_decorations,
maybe_old_stacking_context_tree,
); );
} }
@ -965,6 +1008,7 @@ impl BoxFragment {
containing_block_info: &ContainingBlockInfo, containing_block_info: &ContainingBlockInfo,
parent_stacking_context: &mut StackingContext, parent_stacking_context: &mut StackingContext,
text_decorations: &Arc<Vec<FragmentTextDecoration>>, text_decorations: &Arc<Vec<FragmentTextDecoration>>,
maybe_old_stacking_context_tree: &Option<Box<StackingContextTree>>,
) { ) {
let reference_frame_data = let reference_frame_data =
match self.reference_frame_data_if_necessary(&containing_block.rect) { match self.reference_frame_data_if_necessary(&containing_block.rect) {
@ -977,6 +1021,7 @@ impl BoxFragment {
containing_block_info, containing_block_info,
parent_stacking_context, parent_stacking_context,
text_decorations, text_decorations,
maybe_old_stacking_context_tree,
); );
}, },
}; };
@ -1027,9 +1072,12 @@ impl BoxFragment {
&new_containing_block_info, &new_containing_block_info,
parent_stacking_context, parent_stacking_context,
text_decorations, text_decorations,
maybe_old_stacking_context_tree,
); );
} }
// MYNOTES: fix this
#[allow(clippy::too_many_arguments)]
fn build_stacking_context_tree_maybe_creating_stacking_context( fn build_stacking_context_tree_maybe_creating_stacking_context(
&self, &self,
fragment: Fragment, fragment: Fragment,
@ -1038,6 +1086,7 @@ impl BoxFragment {
containing_block_info: &ContainingBlockInfo, containing_block_info: &ContainingBlockInfo,
parent_stacking_context: &mut StackingContext, parent_stacking_context: &mut StackingContext,
text_decorations: &Arc<Vec<FragmentTextDecoration>>, text_decorations: &Arc<Vec<FragmentTextDecoration>>,
maybe_old_stacking_context_tree: &Option<Box<StackingContextTree>>,
) { ) {
let context_type = match self.get_stacking_context_type() { let context_type = match self.get_stacking_context_type() {
Some(context_type) => context_type, Some(context_type) => context_type,
@ -1049,6 +1098,7 @@ impl BoxFragment {
containing_block_info, containing_block_info,
parent_stacking_context, parent_stacking_context,
text_decorations, text_decorations,
maybe_old_stacking_context_tree,
); );
return; return;
}, },
@ -1103,6 +1153,7 @@ impl BoxFragment {
containing_block_info, containing_block_info,
&mut child_stacking_context, &mut child_stacking_context,
text_decorations, text_decorations,
maybe_old_stacking_context_tree,
); );
let mut stolen_children = vec![]; let mut stolen_children = vec![];
@ -1121,6 +1172,8 @@ impl BoxFragment {
.append(&mut stolen_children); .append(&mut stolen_children);
} }
// MYNOTES: fix this
#[allow(clippy::too_many_arguments)]
fn build_stacking_context_tree_for_children( fn build_stacking_context_tree_for_children(
&self, &self,
fragment: Fragment, fragment: Fragment,
@ -1129,6 +1182,7 @@ impl BoxFragment {
containing_block_info: &ContainingBlockInfo, containing_block_info: &ContainingBlockInfo,
stacking_context: &mut StackingContext, stacking_context: &mut StackingContext,
text_decorations: &Arc<Vec<FragmentTextDecoration>>, text_decorations: &Arc<Vec<FragmentTextDecoration>>,
maybe_old_stacking_context_tree: &Option<Box<StackingContextTree>>,
) { ) {
let mut new_scroll_node_id = containing_block.scroll_node_id; let mut new_scroll_node_id = containing_block.scroll_node_id;
let mut new_clip_id = containing_block.clip_id; let mut new_clip_id = containing_block.clip_id;
@ -1213,6 +1267,7 @@ impl BoxFragment {
&new_scroll_node_id, &new_scroll_node_id,
new_clip_id, new_clip_id,
&containing_block.rect, &containing_block.rect,
maybe_old_stacking_context_tree,
) { ) {
new_clip_id = overflow_frame_data.clip_id; new_clip_id = overflow_frame_data.clip_id;
if let Some(scroll_frame_data) = overflow_frame_data.scroll_frame_data { if let Some(scroll_frame_data) = overflow_frame_data.scroll_frame_data {
@ -1313,6 +1368,7 @@ impl BoxFragment {
stacking_context, stacking_context,
StackingContextBuildMode::SkipHoisted, StackingContextBuildMode::SkipHoisted,
text_decorations, text_decorations,
maybe_old_stacking_context_tree,
); );
} }
@ -1375,6 +1431,7 @@ impl BoxFragment {
parent_scroll_node_id: &ScrollTreeNodeId, parent_scroll_node_id: &ScrollTreeNodeId,
parent_clip_id: ClipId, parent_clip_id: ClipId,
containing_block_rect: &PhysicalRect<Au>, containing_block_rect: &PhysicalRect<Au>,
maybe_old_stacking_context_tree: &Option<Box<StackingContextTree>>,
) -> Option<OverflowFrameData> { ) -> Option<OverflowFrameData> {
let overflow = self.style.effective_overflow(self.base.flags); let overflow = self.style.effective_overflow(self.base.flags);
@ -1476,6 +1533,7 @@ impl BoxFragment {
content_rect, content_rect,
scroll_frame_rect, scroll_frame_rect,
sensitivity, sensitivity,
maybe_old_stacking_context_tree,
); );
Some(OverflowFrameData { Some(OverflowFrameData {
@ -1702,6 +1760,7 @@ impl PositioningFragment {
containing_block_info: &ContainingBlockInfo, containing_block_info: &ContainingBlockInfo,
stacking_context: &mut StackingContext, stacking_context: &mut StackingContext,
text_decorations: &Arc<Vec<FragmentTextDecoration>>, text_decorations: &Arc<Vec<FragmentTextDecoration>>,
maybe_old_stacking_context_tree: &Option<Box<StackingContextTree>>,
) { ) {
let rect = self let rect = self
.rect .rect
@ -1717,6 +1776,7 @@ impl PositioningFragment {
stacking_context, stacking_context,
StackingContextBuildMode::SkipHoisted, StackingContextBuildMode::SkipHoisted,
text_decorations, text_decorations,
maybe_old_stacking_context_tree,
); );
} }
} }

View file

@ -389,22 +389,27 @@ impl Layout for LayoutThread {
process_node_scroll_area_request(node, self.fragment_tree.borrow().clone()) process_node_scroll_area_request(node, self.fragment_tree.borrow().clone())
} }
// #[cfg_attr( #[cfg_attr(
// feature = "tracing", feature = "tracing",
// tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace") tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace")
// )] )]
fn query_scroll_offset(&self, node: OpaqueNode) -> LayoutVector2D { fn query_scroll_offset(&self, node: OpaqueNode) -> LayoutVector2D {
let scroll_id = ExternalScrollId( let scroll_id = ExternalScrollId(
combine_id_with_fragment_type(node.id(), FragmentType::FragmentBody), combine_id_with_fragment_type(node.id(), FragmentType::FragmentBody),
self.id.into(), self.id.into(),
); );
self.cached_scroll_tree().and_then(|tree| { self.cached_scroll_tree()
tree.get_node_by_external_scroll_id(&scroll_id) .and_then(|tree| {
.map(|scroll_node| match &scroll_node.info { tree.get_node_by_external_scroll_id(&scroll_id).map(
SpatialTreeNodeInfo::Scroll(spatial_scroll_node) => spatial_scroll_node.offset, |scroll_node| match &scroll_node.info {
_ => Default::default(), SpatialTreeNodeInfo::Scroll(spatial_scroll_node) => {
spatial_scroll_node.offset
},
_ => Default::default(),
},
)
}) })
}).unwrap_or_default() .unwrap_or_default()
} }
/// Step 1-4 of <https://drafts.csswg.org/cssom-view/#element-scrolling-members> /// Step 1-4 of <https://drafts.csswg.org/cssom-view/#element-scrolling-members>
@ -514,7 +519,11 @@ impl Layout for LayoutThread {
fn set_scroll_offsets(&mut self, scroll_states: &[ScrollState]) { fn set_scroll_offsets(&mut self, scroll_states: &[ScrollState]) {
if let Some(mut tree) = self.cached_scroll_tree_mut() { if let Some(mut tree) = self.cached_scroll_tree_mut() {
for ScrollState {scroll_id, scroll_offset} in scroll_states { for ScrollState {
scroll_id,
scroll_offset,
} in scroll_states
{
tree.set_scroll_offsets_for_node_with_external_scroll_id(scroll_id, *scroll_offset); tree.set_scroll_offsets_for_node_with_external_scroll_id(scroll_id, *scroll_offset);
} }
} }
@ -687,7 +696,7 @@ impl LayoutThread {
highlighted_dom_node: reflow_request.highlighted_dom_node, highlighted_dom_node: reflow_request.highlighted_dom_node,
}; };
let damage = self.restyle_and_build_trees( let (damage, maybe_old_stacking_context_tree) = self.restyle_and_build_trees(
&reflow_request, &reflow_request,
root_element, root_element,
rayon_pool, rayon_pool,
@ -695,7 +704,7 @@ impl LayoutThread {
viewport_changed, viewport_changed,
); );
self.calculate_overflow(damage); self.calculate_overflow(damage);
self.build_stacking_context_tree(&reflow_request, damage); self.build_stacking_context_tree(&reflow_request, damage, &maybe_old_stacking_context_tree);
self.build_display_list(&reflow_request, &mut layout_context); self.build_display_list(&reflow_request, &mut layout_context);
self.first_reflow.set(false); self.first_reflow.set(false);
@ -777,10 +786,10 @@ impl LayoutThread {
.flush(guards, Some(root_element), Some(snapshot_map)); .flush(guards, Some(root_element), Some(snapshot_map));
} }
#[cfg_attr( // #[cfg_attr(
feature = "tracing", // feature = "tracing",
tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace") // tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace")
)] // )]
fn restyle_and_build_trees( fn restyle_and_build_trees(
&self, &self,
reflow_request: &ReflowRequest, reflow_request: &ReflowRequest,
@ -788,7 +797,7 @@ impl LayoutThread {
rayon_pool: Option<&ThreadPool>, rayon_pool: Option<&ThreadPool>,
layout_context: &mut LayoutContext<'_>, layout_context: &mut LayoutContext<'_>,
viewport_changed: bool, viewport_changed: bool,
) -> RestyleDamage { ) -> (RestyleDamage, Option<Box<StackingContextTree>>) {
let dirty_root = unsafe { let dirty_root = unsafe {
ServoLayoutNode::new(&reflow_request.dirty_root.unwrap()) ServoLayoutNode::new(&reflow_request.dirty_root.unwrap())
.as_element() .as_element()
@ -804,7 +813,7 @@ impl LayoutThread {
if !token.should_traverse() { if !token.should_traverse() {
layout_context.style_context.stylist.rule_tree().maybe_gc(); layout_context.style_context.stylist.rule_tree().maybe_gc();
return RestyleDamage::empty(); return (RestyleDamage::empty(), None);
} }
let dirty_root: ServoLayoutNode = let dirty_root: ServoLayoutNode =
@ -817,7 +826,7 @@ impl LayoutThread {
damage = RestyleDamage::REBUILD_BOX; damage = RestyleDamage::REBUILD_BOX;
} else if !damage.contains(RestyleDamage::REBUILD_BOX) { } else if !damage.contains(RestyleDamage::REBUILD_BOX) {
layout_context.style_context.stylist.rule_tree().maybe_gc(); layout_context.style_context.stylist.rule_tree().maybe_gc();
return damage; return (damage, None);
} }
let mut box_tree = self.box_tree.borrow_mut(); let mut box_tree = self.box_tree.borrow_mut();
@ -853,7 +862,7 @@ impl LayoutThread {
// The FragmentTree has been updated, so any existing StackingContext tree that layout // The FragmentTree has been updated, so any existing StackingContext tree that layout
// had is now out of date and should be rebuilt. // had is now out of date and should be rebuilt.
*self.stacking_context_tree.borrow_mut() = None; let old_stacking_context_tree = self.stacking_context_tree.borrow_mut().take();
if self.debug.dump_style_tree { if self.debug.dump_style_tree {
println!( println!(
@ -872,7 +881,7 @@ impl LayoutThread {
// GC the rule tree if some heuristics are met. // GC the rule tree if some heuristics are met.
layout_context.style_context.stylist.rule_tree().maybe_gc(); layout_context.style_context.stylist.rule_tree().maybe_gc();
damage (damage, old_stacking_context_tree.map(Box::new))
} }
fn calculate_overflow(&self, damage: RestyleDamage) { fn calculate_overflow(&self, damage: RestyleDamage) {
@ -888,7 +897,12 @@ impl LayoutThread {
} }
} }
fn build_stacking_context_tree(&self, reflow_request: &ReflowRequest, damage: RestyleDamage) { fn build_stacking_context_tree(
&self,
reflow_request: &ReflowRequest,
damage: RestyleDamage,
maybe_old_stacking_context_tree: &Option<Box<StackingContextTree>>,
) {
if !reflow_request.reflow_goal.needs_display_list() && if !reflow_request.reflow_goal.needs_display_list() &&
!reflow_request.reflow_goal.needs_display() !reflow_request.reflow_goal.needs_display()
{ {
@ -926,6 +940,7 @@ impl LayoutThread {
fragment_tree.viewport_scroll_sensitivity, fragment_tree.viewport_scroll_sensitivity,
self.first_reflow.get(), self.first_reflow.get(),
&self.debug, &self.debug,
maybe_old_stacking_context_tree,
)); ));
} }
@ -957,6 +972,7 @@ impl LayoutThread {
fragment_tree, fragment_tree,
&self.debug, &self.debug,
); );
self.compositor_api.send_display_list( self.compositor_api.send_display_list(
self.webview_id, self.webview_id,
&stacking_context_tree.compositor_info, &stacking_context_tree.compositor_info,
@ -989,21 +1005,24 @@ impl LayoutThread {
if stacking_context_tree.is_none() { if stacking_context_tree.is_none() {
return None; return None;
} }
Some(RefMut::map(stacking_context_tree, |stacking_context_tree| { Some(RefMut::map(
&mut stacking_context_tree stacking_context_tree,
.as_mut() |stacking_context_tree| {
.expect("Uninitialized stacking context tree") &mut stacking_context_tree
.compositor_info .as_mut()
.scroll_tree .expect("Uninitialized stacking context tree")
})) .compositor_info
.scroll_tree
},
))
} }
fn update_scroll_node_state(&self, state: &ScrollState) { fn update_scroll_node_state(&self, state: &ScrollState) {
if let Some(mut tree) = self.cached_scroll_tree_mut() { if let Some(mut tree) = self.cached_scroll_tree_mut() {
tree.set_scroll_offsets_for_node_with_external_scroll_id( tree.set_scroll_offsets_for_node_with_external_scroll_id(
&state.scroll_id, &state.scroll_id,
state.scroll_offset, state.scroll_offset,
); );
self.compositor_api.send_scroll_node( self.compositor_api.send_scroll_node(
self.webview_id, self.webview_id,
self.id.into(), self.id.into(),

View file

@ -1930,7 +1930,10 @@ impl ScriptThread {
for scroll_state in scroll_states.into_iter() { for scroll_state in scroll_states.into_iter() {
if scroll_state.scroll_id.is_root() { if scroll_state.scroll_id.is_root() {
window.update_viewport_for_scroll(-scroll_state.scroll_offset.x, -scroll_state.scroll_offset.y); window.update_viewport_for_scroll(
-scroll_state.scroll_offset.x,
-scroll_state.scroll_offset.y,
);
} }
} }
}, },

View file

@ -264,11 +264,12 @@ impl ScrollTree {
parent: Option<&ScrollTreeNodeId>, parent: Option<&ScrollTreeNodeId>,
info: SpatialTreeNodeInfo, info: SpatialTreeNodeInfo,
) -> ScrollTreeNodeId { ) -> ScrollTreeNodeId {
let new_scroll_id = ScrollTreeNodeId { let new_scroll_id = ScrollTreeNodeId {
index: self.nodes.len(), index: self.nodes.len(),
}; };
if let SpatialTreeNodeInfo::Scroll(spatial_scroll_node) = &info { if let SpatialTreeNodeInfo::Scroll(spatial_scroll_node) = &info {
self.external_scroll_id_to_node_id.insert(spatial_scroll_node.external_id, new_scroll_id); self.external_scroll_id_to_node_id
.insert(spatial_scroll_node.external_id, new_scroll_id);
} }
self.nodes.push(ScrollTreeNode { self.nodes.push(ScrollTreeNode {
@ -370,6 +371,9 @@ impl ScrollTree {
} }
false false
} }
// Update this stacking context
pub fn persevere_old_stacking_context_tree_scroll() {}
} }
/// A data structure which stores compositor-side information about /// A data structure which stores compositor-side information about