mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
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:
parent
c936dd6c4e
commit
de780dcde4
18 changed files with 257 additions and 233 deletions
|
@ -13,7 +13,7 @@ use crate::layout_debug::DebugId;
|
|||
/// This data structure stores fields that are common to all non-base
|
||||
/// Fragment types and should generally be the first member of all
|
||||
/// concrete fragments.
|
||||
#[derive(Debug, Serialize)]
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub(crate) struct BaseFragment {
|
||||
/// A tag which identifies the DOM node and pseudo element of this
|
||||
/// Fragment's content. If this fragment isn't related to any DOM
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use app_units::Au;
|
||||
use atomic_refcell::AtomicRefCell;
|
||||
use base::print_tree::PrintTree;
|
||||
use serde::Serialize;
|
||||
use servo_arc::Arc as ServoArc;
|
||||
|
@ -13,7 +14,6 @@ use style::properties::ComputedValues;
|
|||
use style::Zero;
|
||||
|
||||
use super::{BaseFragment, BaseFragmentInfo, CollapsedBlockMargins, Fragment};
|
||||
use crate::cell::ArcRefCell;
|
||||
use crate::formatting_contexts::Baselines;
|
||||
use crate::fragment_tree::FragmentFlags;
|
||||
use crate::geom::{
|
||||
|
@ -53,7 +53,7 @@ pub(crate) struct BoxFragment {
|
|||
|
||||
#[serde(skip_serializing)]
|
||||
pub style: ServoArc<ComputedValues>,
|
||||
pub children: Vec<ArcRefCell<Fragment>>,
|
||||
pub children: Vec<Fragment>,
|
||||
|
||||
/// The content rect of this fragment in the parent fragment's content rectangle. This
|
||||
/// does not include padding, border, or margin -- it only includes content.
|
||||
|
@ -84,7 +84,8 @@ pub(crate) struct BoxFragment {
|
|||
/// The resolved box insets if this box is `position: sticky`. These are calculated
|
||||
/// during stacking context tree construction because they rely on the size of the
|
||||
/// scroll container.
|
||||
pub(crate) resolved_sticky_insets: Option<PhysicalSides<AuOrAuto>>,
|
||||
#[serde(skip_serializing)]
|
||||
pub(crate) resolved_sticky_insets: AtomicRefCell<Option<PhysicalSides<AuOrAuto>>>,
|
||||
|
||||
#[serde(skip_serializing)]
|
||||
pub background_mode: BackgroundMode,
|
||||
|
@ -115,7 +116,7 @@ impl BoxFragment {
|
|||
BoxFragment {
|
||||
base: base_fragment_info.into(),
|
||||
style,
|
||||
children: children.into_iter().map(ArcRefCell::new).collect(),
|
||||
children,
|
||||
content_rect,
|
||||
padding,
|
||||
border,
|
||||
|
@ -124,7 +125,7 @@ impl BoxFragment {
|
|||
baselines: Baselines::default(),
|
||||
block_margins_collapsed_with_children,
|
||||
scrollable_overflow_from_children,
|
||||
resolved_sticky_insets: None,
|
||||
resolved_sticky_insets: AtomicRefCell::default(),
|
||||
background_mode: BackgroundMode::Normal,
|
||||
detailed_layout_info: None,
|
||||
}
|
||||
|
@ -234,7 +235,7 @@ impl BoxFragment {
|
|||
));
|
||||
|
||||
for child in &self.children {
|
||||
child.borrow().print(tree);
|
||||
child.print(tree);
|
||||
}
|
||||
tree.end_level();
|
||||
}
|
||||
|
@ -278,7 +279,7 @@ impl BoxFragment {
|
|||
"Should not call this method on statically positioned box."
|
||||
);
|
||||
|
||||
if let Some(resolved_sticky_insets) = self.resolved_sticky_insets {
|
||||
if let Some(resolved_sticky_insets) = *self.resolved_sticky_insets.borrow() {
|
||||
return resolved_sticky_insets;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ pub(crate) struct ContainingBlockManager<'a, T> {
|
|||
impl<'a, T> ContainingBlockManager<'a, T> {
|
||||
pub(crate) fn get_containing_block_for_fragment(&self, fragment: &Fragment) -> &T {
|
||||
if let Fragment::Box(box_fragment) = fragment {
|
||||
match box_fragment.style.clone_position() {
|
||||
match box_fragment.borrow().style.clone_position() {
|
||||
ComputedPosition::Fixed => self.for_absolute_and_fixed_descendants,
|
||||
ComputedPosition::Absolute => self
|
||||
.for_absolute_descendants
|
||||
|
|
|
@ -23,16 +23,16 @@ use crate::cell::ArcRefCell;
|
|||
use crate::geom::{LogicalSides, PhysicalRect};
|
||||
use crate::style_ext::ComputedValuesExt;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[derive(Clone, Serialize)]
|
||||
pub(crate) enum Fragment {
|
||||
Box(BoxFragment),
|
||||
Box(ArcRefCell<BoxFragment>),
|
||||
/// Floating content. A floated fragment is very similar to a normal
|
||||
/// [BoxFragment] but it isn't positioned using normal in block flow
|
||||
/// positioning rules (margin collapse, etc). Instead, they are laid
|
||||
/// out by the [crate::flow::float::SequentialLayoutState] of their
|
||||
/// float containing block formatting context.
|
||||
Float(BoxFragment),
|
||||
Positioning(PositioningFragment),
|
||||
Float(ArcRefCell<BoxFragment>),
|
||||
Positioning(ArcRefCell<PositioningFragment>),
|
||||
/// Absolute and fixed position fragments are hoisted up so that they
|
||||
/// are children of the BoxFragment that establishes their containing
|
||||
/// blocks, so that they can be laid out properly. When this happens
|
||||
|
@ -41,9 +41,9 @@ pub(crate) enum Fragment {
|
|||
/// regard to their original tree order during stacking context tree /
|
||||
/// display list construction.
|
||||
AbsoluteOrFixedPositioned(ArcRefCell<HoistedSharedFragment>),
|
||||
Text(TextFragment),
|
||||
Image(ImageFragment),
|
||||
IFrame(IFrameFragment),
|
||||
Text(ArcRefCell<TextFragment>),
|
||||
Image(ArcRefCell<ImageFragment>),
|
||||
IFrame(ArcRefCell<IFrameFragment>),
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
@ -99,26 +99,26 @@ pub(crate) struct IFrameFragment {
|
|||
}
|
||||
|
||||
impl Fragment {
|
||||
pub fn base(&self) -> Option<&BaseFragment> {
|
||||
pub fn base(&self) -> Option<BaseFragment> {
|
||||
Some(match self {
|
||||
Fragment::Box(fragment) => &fragment.base,
|
||||
Fragment::Text(fragment) => &fragment.base,
|
||||
Fragment::Box(fragment) => fragment.borrow().base.clone(),
|
||||
Fragment::Text(fragment) => fragment.borrow().base.clone(),
|
||||
Fragment::AbsoluteOrFixedPositioned(_) => return None,
|
||||
Fragment::Positioning(fragment) => &fragment.base,
|
||||
Fragment::Image(fragment) => &fragment.base,
|
||||
Fragment::IFrame(fragment) => &fragment.base,
|
||||
Fragment::Float(fragment) => &fragment.base,
|
||||
Fragment::Positioning(fragment) => fragment.borrow().base.clone(),
|
||||
Fragment::Image(fragment) => fragment.borrow().base.clone(),
|
||||
Fragment::IFrame(fragment) => fragment.borrow().base.clone(),
|
||||
Fragment::Float(fragment) => fragment.borrow().base.clone(),
|
||||
})
|
||||
}
|
||||
pub(crate) fn content_rect_mut(&mut self) -> Option<&mut PhysicalRect<Au>> {
|
||||
pub(crate) fn mutate_content_rect(&mut self, callback: impl FnOnce(&mut PhysicalRect<Au>)) {
|
||||
match self {
|
||||
Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => {
|
||||
Some(&mut box_fragment.content_rect)
|
||||
callback(&mut box_fragment.borrow_mut().content_rect)
|
||||
},
|
||||
Fragment::Positioning(_) | Fragment::AbsoluteOrFixedPositioned(_) => None,
|
||||
Fragment::Text(text_fragment) => Some(&mut text_fragment.rect),
|
||||
Fragment::Image(image_fragment) => Some(&mut image_fragment.rect),
|
||||
Fragment::IFrame(iframe_fragment) => Some(&mut iframe_fragment.rect),
|
||||
Fragment::Positioning(_) | Fragment::AbsoluteOrFixedPositioned(_) => {},
|
||||
Fragment::Text(text_fragment) => callback(&mut text_fragment.borrow_mut().rect),
|
||||
Fragment::Image(image_fragment) => callback(&mut image_fragment.borrow_mut().rect),
|
||||
Fragment::IFrame(iframe_fragment) => callback(&mut iframe_fragment.borrow_mut().rect),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,25 +128,26 @@ impl Fragment {
|
|||
|
||||
pub fn print(&self, tree: &mut PrintTree) {
|
||||
match self {
|
||||
Fragment::Box(fragment) => fragment.print(tree),
|
||||
Fragment::Box(fragment) => fragment.borrow().print(tree),
|
||||
Fragment::Float(fragment) => {
|
||||
tree.new_level("Float".to_string());
|
||||
fragment.print(tree);
|
||||
fragment.borrow().print(tree);
|
||||
tree.end_level();
|
||||
},
|
||||
Fragment::AbsoluteOrFixedPositioned(_) => {
|
||||
tree.add_item("AbsoluteOrFixedPositioned".to_string());
|
||||
},
|
||||
Fragment::Positioning(fragment) => fragment.print(tree),
|
||||
Fragment::Text(fragment) => fragment.print(tree),
|
||||
Fragment::Image(fragment) => fragment.print(tree),
|
||||
Fragment::IFrame(fragment) => fragment.print(tree),
|
||||
Fragment::Positioning(fragment) => fragment.borrow().print(tree),
|
||||
Fragment::Text(fragment) => fragment.borrow().print(tree),
|
||||
Fragment::Image(fragment) => fragment.borrow().print(tree),
|
||||
Fragment::IFrame(fragment) => fragment.borrow().print(tree),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scrolling_area(&self, containing_block: &PhysicalRect<Au>) -> PhysicalRect<Au> {
|
||||
match self {
|
||||
Fragment::Box(fragment) | Fragment::Float(fragment) => fragment
|
||||
.borrow()
|
||||
.scrollable_overflow()
|
||||
.translate(containing_block.origin.to_vector()),
|
||||
_ => self.scrollable_overflow(),
|
||||
|
@ -156,13 +157,13 @@ impl Fragment {
|
|||
pub fn scrollable_overflow(&self) -> PhysicalRect<Au> {
|
||||
match self {
|
||||
Fragment::Box(fragment) | Fragment::Float(fragment) => {
|
||||
fragment.scrollable_overflow_for_parent()
|
||||
fragment.borrow().scrollable_overflow_for_parent()
|
||||
},
|
||||
Fragment::AbsoluteOrFixedPositioned(_) => PhysicalRect::zero(),
|
||||
Fragment::Positioning(fragment) => fragment.scrollable_overflow,
|
||||
Fragment::Text(fragment) => fragment.rect,
|
||||
Fragment::Image(fragment) => fragment.rect,
|
||||
Fragment::IFrame(fragment) => fragment.rect,
|
||||
Fragment::Positioning(fragment) => fragment.borrow().scrollable_overflow,
|
||||
Fragment::Text(fragment) => fragment.borrow().rect,
|
||||
Fragment::Image(fragment) => fragment.borrow().rect,
|
||||
Fragment::IFrame(fragment) => fragment.borrow().rect,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,6 +180,7 @@ impl Fragment {
|
|||
|
||||
match self {
|
||||
Fragment::Box(fragment) | Fragment::Float(fragment) => {
|
||||
let fragment = fragment.borrow();
|
||||
let content_rect = fragment
|
||||
.content_rect
|
||||
.translate(containing_block.origin.to_vector());
|
||||
|
@ -202,15 +204,16 @@ impl Fragment {
|
|||
fragment
|
||||
.children
|
||||
.iter()
|
||||
.find_map(|child| child.borrow().find(&new_manager, level + 1, process_func))
|
||||
.find_map(|child| child.find(&new_manager, level + 1, process_func))
|
||||
},
|
||||
Fragment::Positioning(fragment) => {
|
||||
let fragment = fragment.borrow();
|
||||
let content_rect = fragment.rect.translate(containing_block.origin.to_vector());
|
||||
let new_manager = manager.new_for_non_absolute_descendants(&content_rect);
|
||||
fragment
|
||||
.children
|
||||
.iter()
|
||||
.find_map(|child| child.borrow().find(&new_manager, level + 1, process_func))
|
||||
.find_map(|child| child.find(&new_manager, level + 1, process_func))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ use style::logical_geometry::WritingMode;
|
|||
use style::values::specified::align::AlignFlags;
|
||||
|
||||
use super::Fragment;
|
||||
use crate::cell::ArcRefCell;
|
||||
use crate::geom::{LogicalVec2, PhysicalRect, PhysicalVec};
|
||||
|
||||
/// A reference to a Fragment which is shared between `HoistedAbsolutelyPositionedBox`
|
||||
|
@ -16,7 +15,7 @@ use crate::geom::{LogicalVec2, PhysicalRect, PhysicalVec};
|
|||
/// This will be used later in order to paint this hoisted box in tree order.
|
||||
#[derive(Serialize)]
|
||||
pub(crate) struct HoistedSharedFragment {
|
||||
pub fragment: Option<ArcRefCell<Fragment>>,
|
||||
pub fragment: Option<Fragment>,
|
||||
/// The "static-position rect" of this absolutely positioned box. This is defined by the
|
||||
/// layout mode from which the box originates.
|
||||
///
|
||||
|
|
|
@ -19,7 +19,7 @@ use crate::geom::PhysicalRect;
|
|||
pub(crate) struct PositioningFragment {
|
||||
pub base: BaseFragment,
|
||||
pub rect: PhysicalRect<Au>,
|
||||
pub children: Vec<ArcRefCell<Fragment>>,
|
||||
pub children: Vec<Fragment>,
|
||||
/// The scrollable overflow of this anonymous fragment's children.
|
||||
pub scrollable_overflow: PhysicalRect<Au>,
|
||||
|
||||
|
@ -29,7 +29,7 @@ pub(crate) struct PositioningFragment {
|
|||
}
|
||||
|
||||
impl PositioningFragment {
|
||||
pub fn new_anonymous(rect: PhysicalRect<Au>, children: Vec<Fragment>) -> Self {
|
||||
pub fn new_anonymous(rect: PhysicalRect<Au>, children: Vec<Fragment>) -> ArcRefCell<Self> {
|
||||
Self::new_with_base_fragment(BaseFragment::anonymous(), None, rect, children)
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ impl PositioningFragment {
|
|||
base_fragment_info: BaseFragmentInfo,
|
||||
rect: PhysicalRect<Au>,
|
||||
style: ServoArc<ComputedValues>,
|
||||
) -> Self {
|
||||
) -> ArcRefCell<Self> {
|
||||
Self::new_with_base_fragment(base_fragment_info.into(), Some(style), rect, Vec::new())
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ impl PositioningFragment {
|
|||
style: Option<ServoArc<ComputedValues>>,
|
||||
rect: PhysicalRect<Au>,
|
||||
children: Vec<Fragment>,
|
||||
) -> Self {
|
||||
) -> ArcRefCell<Self> {
|
||||
let content_origin = rect.origin;
|
||||
let scrollable_overflow = children.iter().fold(PhysicalRect::zero(), |acc, child| {
|
||||
acc.union(
|
||||
|
@ -55,13 +55,13 @@ impl PositioningFragment {
|
|||
.translate(content_origin.to_vector()),
|
||||
)
|
||||
});
|
||||
PositioningFragment {
|
||||
ArcRefCell::new(PositioningFragment {
|
||||
base,
|
||||
style,
|
||||
rect,
|
||||
children: children.into_iter().map(ArcRefCell::new).collect(),
|
||||
children,
|
||||
scrollable_overflow,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn print(&self, tree: &mut PrintTree) {
|
||||
|
@ -74,7 +74,7 @@ impl PositioningFragment {
|
|||
));
|
||||
|
||||
for child in &self.children {
|
||||
child.borrow().print(tree);
|
||||
child.print(tree);
|
||||
}
|
||||
tree.end_level();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue