diff options
Diffstat (limited to 'components/layout/layout_impl.rs')
-rw-r--r-- | components/layout/layout_impl.rs | 125 |
1 files changed, 72 insertions, 53 deletions
diff --git a/components/layout/layout_impl.rs b/components/layout/layout_impl.rs index fcf658036b2..b490b4a0506 100644 --- a/components/layout/layout_impl.rs +++ b/components/layout/layout_impl.rs @@ -77,7 +77,7 @@ use webrender_api::units::{DevicePixel, DevicePoint, LayoutPixel, LayoutPoint, L use webrender_api::{ExternalScrollId, HitTestFlags}; use crate::context::LayoutContext; -use crate::display_list::{DisplayList, WebRenderImageInfo}; +use crate::display_list::{DisplayListBuilder, StackingContextTree, WebRenderImageInfo}; use crate::query::{ get_the_text_steps, process_client_rect_request, process_content_box_request, process_content_boxes_request, process_node_scroll_area_request, process_offset_parent_query, @@ -144,6 +144,9 @@ pub struct LayoutThread { /// The fragment tree. fragment_tree: RefCell<Option<Arc<FragmentTree>>>, + /// The [`StackingContextTree`] cached from previous layouts. + stacking_context_tree: RefCell<Option<StackingContextTree>>, + /// A counter for epoch messages epoch: Cell<Epoch>, @@ -521,6 +524,7 @@ impl LayoutThread { first_reflow: Cell::new(true), box_tree: Default::default(), fragment_tree: Default::default(), + stacking_context_tree: Default::default(), // Epoch starts at 1 because of the initial display list for epoch 0 that we send to WR epoch: Cell::new(Epoch(1)), viewport_size: Size2D::new( @@ -649,15 +653,17 @@ impl LayoutThread { highlighted_dom_node: reflow_request.highlighted_dom_node, }; - self.restyle_and_build_trees( + let did_reflow = self.restyle_and_build_trees( &reflow_request, root_element, rayon_pool, &mut layout_context, ); + + self.build_stacking_context_tree(&reflow_request, did_reflow); self.build_display_list(&reflow_request, &mut layout_context); - self.first_reflow.set(false); + self.first_reflow.set(false); if let ReflowGoal::UpdateScrollNode(scroll_state) = reflow_request.reflow_goal { self.update_scroll_node_state(&scroll_state); } @@ -666,6 +672,7 @@ impl LayoutThread { let iframe_sizes = std::mem::take(&mut *layout_context.iframe_sizes.lock()); let node_to_image_animation_map = std::mem::take(&mut *layout_context.node_image_animation_map.write()); + Some(ReflowResult { pending_images, iframe_sizes, @@ -742,7 +749,7 @@ impl LayoutThread { root_element: ServoLayoutElement<'_>, rayon_pool: Option<&ThreadPool>, layout_context: &mut LayoutContext<'_>, - ) { + ) -> bool { let dirty_root = unsafe { ServoLayoutNode::new(&reflow_request.dirty_root.unwrap()) .as_element() @@ -758,7 +765,7 @@ impl LayoutThread { if !token.should_traverse() { layout_context.style_context.stylist.rule_tree().maybe_gc(); - return; + return false; } let dirty_root: ServoLayoutNode = @@ -768,7 +775,7 @@ impl LayoutThread { let damage = compute_damage_and_repair_style(layout_context.shared_context(), root_node); if damage == RestyleDamage::REPAINT { layout_context.style_context.stylist.rule_tree().maybe_gc(); - return; + return false; } let mut box_tree = self.box_tree.borrow_mut(); @@ -803,8 +810,15 @@ impl LayoutThread { run_layout() }); + if self.debug.dump_flow_tree { + fragment_tree.print(); + } *self.fragment_tree.borrow_mut() = Some(fragment_tree); + // The FragmentTree has been updated, so any existing StackingContext tree that layout + // had is now out of date and should be rebuilt. + *self.stacking_context_tree.borrow_mut() = None; + if self.debug.dump_style_tree { println!( "{:?}", @@ -822,75 +836,80 @@ impl LayoutThread { // GC the rule tree if some heuristics are met. layout_context.style_context.stylist.rule_tree().maybe_gc(); + true } - fn build_display_list( - &self, - reflow_request: &ReflowRequest, - layout_context: &mut LayoutContext<'_>, - ) { + fn build_stacking_context_tree(&self, reflow_request: &ReflowRequest, did_reflow: bool) { + if !reflow_request.reflow_goal.needs_display_list() && + !reflow_request.reflow_goal.needs_display() + { + return; + } let Some(fragment_tree) = &*self.fragment_tree.borrow() else { return; }; - if !reflow_request.reflow_goal.needs_display_list() { + if !did_reflow && self.stacking_context_tree.borrow().is_some() { return; } - let mut epoch = self.epoch.get(); - epoch.next(); - self.epoch.set(epoch); - let viewport_size = LayoutSize::from_untyped(Size2D::new( self.viewport_size.width.to_f32_px(), self.viewport_size.height.to_f32_px(), )); - let mut display_list = DisplayList::new( + + // Build the StackingContextTree. This turns the `FragmentTree` into a + // tree of fragments in CSS painting order and also creates all + // applicable spatial and clip nodes. + *self.stacking_context_tree.borrow_mut() = Some(StackingContextTree::new( + fragment_tree, viewport_size, fragment_tree.scrollable_overflow(), self.id.into(), - epoch.into(), fragment_tree.viewport_scroll_sensitivity, self.first_reflow.get(), - ); - display_list.wr.begin(); - - // `dump_serialized_display_list` doesn't actually print anything. It sets up - // the display list for printing the serialized version when `finalize()` is called. - // We need to call this before adding any display items so that they are printed - // during `finalize()`. - if self.debug.dump_display_list { - display_list.wr.dump_serialized_display_list(); - } + &self.debug, + )); + } - // Build the root stacking context. This turns the `FragmentTree` into a - // tree of fragments in CSS painting order and also creates all - // applicable spatial and clip nodes. - let root_stacking_context = - display_list.build_stacking_context_tree(fragment_tree, &self.debug); + fn build_display_list( + &self, + reflow_request: &ReflowRequest, + layout_context: &mut LayoutContext<'_>, + ) { + if !reflow_request.reflow_goal.needs_display() { + return; + } + let Some(fragment_tree) = &*self.fragment_tree.borrow() else { + return; + }; - // Build the rest of the display list which inclues all of the WebRender primitives. - display_list.build(layout_context, fragment_tree, &root_stacking_context); + let mut stacking_context_tree = self.stacking_context_tree.borrow_mut(); + let Some(stacking_context_tree) = stacking_context_tree.as_mut() else { + return; + }; - if self.debug.dump_flow_tree { - fragment_tree.print(); - } - if self.debug.dump_stacking_context_tree { - root_stacking_context.debug_print(); - } + let mut epoch = self.epoch.get(); + epoch.next(); + self.epoch.set(epoch); + stacking_context_tree.compositor_info.epoch = epoch.into(); - if reflow_request.reflow_goal.needs_display() { - self.compositor_api.send_display_list( - self.webview_id, - display_list.compositor_info, - display_list.wr.end().1, - ); + let built_display_list = DisplayListBuilder::build( + layout_context, + stacking_context_tree, + fragment_tree, + &self.debug, + ); + self.compositor_api.send_display_list( + self.webview_id, + &stacking_context_tree.compositor_info, + built_display_list, + ); - let (keys, instance_keys) = self - .font_context - .collect_unused_webrender_resources(false /* all */); - self.compositor_api - .remove_unused_font_resources(keys, instance_keys) - } + let (keys, instance_keys) = self + .font_context + .collect_unused_webrender_resources(false /* all */); + self.compositor_api + .remove_unused_font_resources(keys, instance_keys) } fn update_scroll_node_state(&self, state: &ScrollState) { |