layout: Make Fragment hold ArcRefCell inside (#34923)

Push the interior mutability into enum variants of `Fragment`, so that
they can be cloned. This saves memory in the `Fragment` tree as the
`Fragment` enum is now a relatively wee 16 bytes and the interior parts
can be a variety of sizes. Before, every `Fragment` was the size of the
biggest kind (`BoxFragment` - 248 bytes).

This a step on the way toward incremental layout.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Martin Robinson 2025-01-13 10:59:59 +01:00 committed by GitHub
parent c936dd6c4e
commit de780dcde4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 257 additions and 233 deletions

View file

@ -13,7 +13,6 @@ use webrender_api::units;
use webrender_traits::display_list::ScrollSensitivity;
use super::{ContainingBlockManager, Fragment, Tag};
use crate::cell::ArcRefCell;
use crate::display_list::StackingContext;
use crate::flow::CanvasBackground;
use crate::geom::PhysicalRect;
@ -28,7 +27,7 @@ pub struct FragmentTree {
/// * The first fragment is generated by the root element.
/// * There may be additional fragments generated by positioned boxes
/// that have the initial containing block.
pub(crate) root_fragments: Vec<ArcRefCell<Fragment>>,
pub(crate) root_fragments: Vec<Fragment>,
/// The scrollable overflow rectangle for the entire tree
/// <https://drafts.csswg.org/css-overflow/#scrollable>
@ -63,7 +62,7 @@ impl FragmentTree {
pub fn print(&self) {
let mut print_tree = PrintTree::new("Fragment Tree".to_string());
for fragment in &self.root_fragments {
fragment.borrow().print(&mut print_tree);
fragment.print(&mut print_tree);
}
}
@ -85,7 +84,7 @@ impl FragmentTree {
};
self.root_fragments
.iter()
.find_map(|child| child.borrow().find(&info, 0, &mut process_func))
.find_map(|child| child.find(&info, 0, &mut process_func))
}
pub fn remove_nodes_in_fragment_tree_from_set(&self, set: &mut FxHashSet<AnimationSetKey>) {
@ -110,9 +109,11 @@ impl FragmentTree {
}
let fragment_relative_rect = match fragment {
Fragment::Box(fragment) | Fragment::Float(fragment) => fragment.border_rect(),
Fragment::Positioning(fragment) => fragment.rect,
Fragment::Text(fragment) => fragment.rect,
Fragment::Box(fragment) | Fragment::Float(fragment) => {
fragment.borrow().border_rect()
},
Fragment::Positioning(fragment) => fragment.borrow().rect,
Fragment::Text(fragment) => fragment.borrow().rect,
Fragment::AbsoluteOrFixedPositioned(_) |
Fragment::Image(_) |
Fragment::IFrame(_) => return None,
@ -140,6 +141,7 @@ impl FragmentTree {
// CSS layout box is inline, return zero." For this check we
// also explicitly ignore the list item portion of the display
// style.
let fragment = fragment.borrow();
if fragment.is_inline_box() {
return Some(Rect::zero());
}
@ -151,7 +153,7 @@ impl FragmentTree {
Size2D::new(padding_rect.size.width, padding_rect.size.height),
)
},
Fragment::Positioning(fragment) => fragment.rect.cast_unit(),
Fragment::Positioning(fragment) => fragment.borrow().rect.cast_unit(),
_ => return None,
};
@ -168,7 +170,6 @@ impl FragmentTree {
let mut scroll_area = self.initial_containing_block;
for fragment in self.root_fragments.iter() {
scroll_area = fragment
.borrow()
.scrolling_area(&self.initial_containing_block)
.union(&scroll_area);
}