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

@ -246,6 +246,7 @@ impl Fragment {
) { ) {
match self { match self {
Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => { Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => {
let box_fragment = &*box_fragment.borrow();
match box_fragment.style.get_inherited_box().visibility { match box_fragment.style.get_inherited_box().visibility {
Visibility::Visible => BuilderForBoxFragment::new( Visibility::Visible => BuilderForBoxFragment::new(
box_fragment, box_fragment,
@ -259,6 +260,7 @@ impl Fragment {
}, },
Fragment::AbsoluteOrFixedPositioned(_) => {}, Fragment::AbsoluteOrFixedPositioned(_) => {},
Fragment::Positioning(positioning_fragment) => { Fragment::Positioning(positioning_fragment) => {
let positioning_fragment = positioning_fragment.borrow();
if let Some(style) = positioning_fragment.style.as_ref() { if let Some(style) = positioning_fragment.style.as_ref() {
let rect = positioning_fragment let rect = positioning_fragment
.rect .rect
@ -272,65 +274,74 @@ impl Fragment {
); );
} }
}, },
Fragment::Image(image) => match image.style.get_inherited_box().visibility { Fragment::Image(image) => {
Visibility::Visible => { let image = image.borrow();
builder.is_contentful = true; match image.style.get_inherited_box().visibility {
Visibility::Visible => {
builder.is_contentful = true;
let image_rendering = image let image_rendering = image
.style .style
.get_inherited_box() .get_inherited_box()
.image_rendering .image_rendering
.to_webrender(); .to_webrender();
let rect = image let rect = image
.rect .rect
.translate(containing_block.origin.to_vector()) .translate(containing_block.origin.to_vector())
.to_webrender(); .to_webrender();
let clip = image let clip = image
.clip .clip
.translate(containing_block.origin.to_vector()) .translate(containing_block.origin.to_vector())
.to_webrender(); .to_webrender();
let common = builder.common_properties(clip, &image.style); let common = builder.common_properties(clip, &image.style);
if let Some(image_key) = image.image_key { if let Some(image_key) = image.image_key {
builder.wr().push_image( builder.wr().push_image(
&common, &common,
rect, rect,
image_rendering, image_rendering,
wr::AlphaType::PremultipliedAlpha, wr::AlphaType::PremultipliedAlpha,
image_key, image_key,
wr::ColorF::WHITE, wr::ColorF::WHITE,
);
}
},
Visibility::Hidden => (),
Visibility::Collapse => (),
}
},
Fragment::IFrame(iframe) => {
let iframe = iframe.borrow();
match iframe.style.get_inherited_box().visibility {
Visibility::Visible => {
builder.is_contentful = true;
let rect = iframe.rect.translate(containing_block.origin.to_vector());
let common = builder.common_properties(rect.to_webrender(), &iframe.style);
builder.wr().push_iframe(
rect.to_webrender(),
common.clip_rect,
&wr::SpaceAndClipInfo {
spatial_id: common.spatial_id,
clip_chain_id: common.clip_chain_id,
},
iframe.pipeline_id.into(),
true,
); );
} },
}, Visibility::Hidden => (),
Visibility::Hidden => (), Visibility::Collapse => (),
Visibility::Collapse => (), }
}, },
Fragment::IFrame(iframe) => match iframe.style.get_inherited_box().visibility { Fragment::Text(text) => {
Visibility::Visible => { let text = &*text.borrow();
builder.is_contentful = true; match text.parent_style.get_inherited_box().visibility {
let rect = iframe.rect.translate(containing_block.origin.to_vector()); Visibility::Visible => {
self.build_display_list_for_text_fragment(text, builder, containing_block)
let common = builder.common_properties(rect.to_webrender(), &iframe.style); },
builder.wr().push_iframe( Visibility::Hidden => (),
rect.to_webrender(), Visibility::Collapse => (),
common.clip_rect, }
&wr::SpaceAndClipInfo {
spatial_id: common.spatial_id,
clip_chain_id: common.clip_chain_id,
},
iframe.pipeline_id.into(),
true,
);
},
Visibility::Hidden => (),
Visibility::Collapse => (),
},
Fragment::Text(t) => match t.parent_style.get_inherited_box().visibility {
Visibility::Visible => {
self.build_display_list_for_text_fragment(t, builder, containing_block)
},
Visibility::Hidden => (),
Visibility::Collapse => (),
}, },
} }
} }

View file

@ -31,7 +31,6 @@ use wr::{ClipChainId, SpatialTreeItemKey, StickyOffsetBounds};
use super::clip_path::build_clip_path_clip_chain_if_necessary; use super::clip_path::build_clip_path_clip_chain_if_necessary;
use super::DisplayList; use super::DisplayList;
use crate::cell::ArcRefCell;
use crate::display_list::conversions::{FilterToWebRender, ToWebRender}; use crate::display_list::conversions::{FilterToWebRender, ToWebRender};
use crate::display_list::{BuilderForBoxFragment, DisplayListBuilder}; use crate::display_list::{BuilderForBoxFragment, DisplayListBuilder};
use crate::fragment_tree::{ use crate::fragment_tree::{
@ -142,8 +141,7 @@ impl DisplayList {
let mut root_stacking_context = StackingContext::create_root(&self.wr, debug); let mut root_stacking_context = StackingContext::create_root(&self.wr, debug);
for fragment in &fragment_tree.root_fragments { for fragment in &fragment_tree.root_fragments {
fragment.borrow_mut().build_stacking_context_tree( fragment.build_stacking_context_tree(
fragment,
self, self,
&containing_block_info, &containing_block_info,
&mut root_stacking_context, &mut root_stacking_context,
@ -260,7 +258,7 @@ pub(crate) enum StackingContextContent {
clip_chain_id: wr::ClipChainId, clip_chain_id: wr::ClipChainId,
section: StackingContextSection, section: StackingContextSection,
containing_block: PhysicalRect<Au>, containing_block: PhysicalRect<Au>,
fragment: ArcRefCell<Fragment>, fragment: Fragment,
is_hit_test_for_scrollable_overflow: bool, is_hit_test_for_scrollable_overflow: bool,
}, },
@ -296,7 +294,7 @@ impl StackingContextContent {
builder.current_scroll_node_id = *scroll_node_id; builder.current_scroll_node_id = *scroll_node_id;
builder.current_reference_frame_scroll_node_id = *reference_frame_scroll_node_id; builder.current_reference_frame_scroll_node_id = *reference_frame_scroll_node_id;
builder.current_clip_chain_id = *clip_chain_id; builder.current_clip_chain_id = *clip_chain_id;
fragment.borrow().build_display_list( fragment.build_display_list(
builder, builder,
containing_block, containing_block,
*section, *section,
@ -632,13 +630,11 @@ impl StackingContext {
else { else {
debug_panic!("Expected a fragment, not a stacking container"); debug_panic!("Expected a fragment, not a stacking container");
}; };
let fragment = fragment.borrow(); let box_fragment = match fragment {
let box_fragment = match &*fragment {
Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => box_fragment, Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => box_fragment,
_ => { _ => debug_panic!("Expected a box-generated fragment"),
debug_panic!("Expected a box-generated fragment");
},
}; };
let box_fragment = &*box_fragment.borrow();
// The `StackingContextFragment` we found is for the root DOM element: // The `StackingContextFragment` we found is for the root DOM element:
debug_assert_eq!( debug_assert_eq!(
@ -849,16 +845,17 @@ pub(crate) enum StackingContextBuildMode {
impl Fragment { impl Fragment {
pub(crate) fn build_stacking_context_tree( pub(crate) fn build_stacking_context_tree(
&mut self, &self,
fragment_ref: &ArcRefCell<Fragment>,
display_list: &mut DisplayList, display_list: &mut DisplayList,
containing_block_info: &ContainingBlockInfo, containing_block_info: &ContainingBlockInfo,
stacking_context: &mut StackingContext, stacking_context: &mut StackingContext,
mode: StackingContextBuildMode, mode: StackingContextBuildMode,
) { ) {
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();
match self { match self {
Fragment::Box(fragment) | Fragment::Float(fragment) => { Fragment::Box(fragment) | Fragment::Float(fragment) => {
let fragment = fragment.borrow();
if mode == StackingContextBuildMode::SkipHoisted && if mode == StackingContextBuildMode::SkipHoisted &&
fragment.style.clone_position().is_absolutely_positioned() fragment.style.clone_position().is_absolutely_positioned()
{ {
@ -876,7 +873,7 @@ impl Fragment {
} }
fragment.build_stacking_context_tree( fragment.build_stacking_context_tree(
fragment_ref, fragment_clone,
display_list, display_list,
containing_block, containing_block,
containing_block_info, containing_block_info,
@ -890,8 +887,7 @@ impl Fragment {
None => unreachable!("Found hoisted box with missing fragment."), None => unreachable!("Found hoisted box with missing fragment."),
}; };
fragment_ref.borrow_mut().build_stacking_context_tree( fragment_ref.build_stacking_context_tree(
fragment_ref,
display_list, display_list,
containing_block_info, containing_block_info,
stacking_context, stacking_context,
@ -899,6 +895,7 @@ impl Fragment {
); );
}, },
Fragment::Positioning(fragment) => { Fragment::Positioning(fragment) => {
let fragment = fragment.borrow();
fragment.build_stacking_context_tree( fragment.build_stacking_context_tree(
display_list, display_list,
containing_block, containing_block,
@ -917,7 +914,7 @@ impl Fragment {
.scroll_node_id, .scroll_node_id,
clip_chain_id: containing_block.clip_chain_id, clip_chain_id: containing_block.clip_chain_id,
containing_block: containing_block.rect, containing_block: containing_block.rect,
fragment: fragment_ref.clone(), fragment: fragment_clone,
is_hit_test_for_scrollable_overflow: false, is_hit_test_for_scrollable_overflow: false,
}); });
}, },
@ -971,8 +968,8 @@ impl BoxFragment {
} }
fn build_stacking_context_tree( fn build_stacking_context_tree(
&mut self, &self,
fragment: &ArcRefCell<Fragment>, fragment: Fragment,
display_list: &mut DisplayList, display_list: &mut DisplayList,
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
containing_block_info: &ContainingBlockInfo, containing_block_info: &ContainingBlockInfo,
@ -988,8 +985,8 @@ impl BoxFragment {
} }
fn build_stacking_context_tree_maybe_creating_reference_frame( fn build_stacking_context_tree_maybe_creating_reference_frame(
&mut self, &self,
fragment: &ArcRefCell<Fragment>, fragment: Fragment,
display_list: &mut DisplayList, display_list: &mut DisplayList,
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
containing_block_info: &ContainingBlockInfo, containing_block_info: &ContainingBlockInfo,
@ -1052,8 +1049,8 @@ impl BoxFragment {
} }
fn build_stacking_context_tree_maybe_creating_stacking_context( fn build_stacking_context_tree_maybe_creating_stacking_context(
&mut self, &self,
fragment: &ArcRefCell<Fragment>, fragment: Fragment,
display_list: &mut DisplayList, display_list: &mut DisplayList,
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
containing_block_info: &ContainingBlockInfo, containing_block_info: &ContainingBlockInfo,
@ -1128,8 +1125,8 @@ impl BoxFragment {
} }
fn build_stacking_context_tree_for_children( fn build_stacking_context_tree_for_children(
&mut self, &self,
fragment: &ArcRefCell<Fragment>, fragment: Fragment,
display_list: &mut DisplayList, display_list: &mut DisplayList,
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
containing_block_info: &ContainingBlockInfo, containing_block_info: &ContainingBlockInfo,
@ -1273,8 +1270,7 @@ impl BoxFragment {
}; };
for child in &self.children { for child in &self.children {
child.borrow_mut().build_stacking_context_tree( child.build_stacking_context_tree(
child,
display_list, display_list,
&new_containing_block_info, &new_containing_block_info,
stacking_context, stacking_context,
@ -1381,7 +1377,7 @@ impl BoxFragment {
} }
fn build_sticky_frame_if_necessary( fn build_sticky_frame_if_necessary(
&mut self, &self,
display_list: &mut DisplayList, display_list: &mut DisplayList,
parent_scroll_node_id: &ScrollTreeNodeId, parent_scroll_node_id: &ScrollTreeNodeId,
containing_block_rect: &PhysicalRect<Au>, containing_block_rect: &PhysicalRect<Au>,
@ -1411,7 +1407,7 @@ impl BoxFragment {
offsets.bottom.map(|v| v.to_used_value(scroll_frame_height)), offsets.bottom.map(|v| v.to_used_value(scroll_frame_height)),
offsets.left.map(|v| v.to_used_value(scroll_frame_width)), offsets.left.map(|v| v.to_used_value(scroll_frame_width)),
); );
self.resolved_sticky_insets = Some(offsets); *self.resolved_sticky_insets.borrow_mut() = Some(offsets);
if scroll_frame_size.is_none() { if scroll_frame_size.is_none() {
return None; return None;
@ -1610,8 +1606,7 @@ impl PositioningFragment {
containing_block_info.new_for_non_absolute_descendants(&new_containing_block); containing_block_info.new_for_non_absolute_descendants(&new_containing_block);
for child in &self.children { for child in &self.children {
child.borrow_mut().build_stacking_context_tree( child.build_stacking_context_tree(
child,
display_list, display_list,
&new_containing_block_info, &new_containing_block_info,
stacking_context, stacking_context,

View file

@ -947,7 +947,7 @@ impl FlexContainer {
// per flex item, in the original order. // per flex item, in the original order.
let (fragment, mut child_positioning_context) = let (fragment, mut child_positioning_context) =
flex_item_fragments.next().unwrap(); flex_item_fragments.next().unwrap();
let fragment = Fragment::Box(fragment); let fragment = Fragment::Box(ArcRefCell::new(fragment));
child_positioning_context.adjust_static_position_of_hoisted_fragments( child_positioning_context.adjust_static_position_of_hoisted_fragments(
&fragment, &fragment,
PositioningContextLength::zero(), PositioningContextLength::zero(),

View file

@ -292,9 +292,9 @@ impl LineItemLayout<'_, '_> {
// We do not know the actual physical position of a logically laid out inline element, until // We do not know the actual physical position of a logically laid out inline element, until
// we know the width of the containing inline block. This step converts the logical rectangle // we know the width of the containing inline block. This step converts the logical rectangle
// into a physical one based on the inline formatting context width. // into a physical one based on the inline formatting context width.
if let Some(content_rect) = fragment.content_rect_mut() { fragment.mutate_content_rect(|content_rect| {
*content_rect = logical_rect.as_physical(Some(self.layout.containing_block)) *content_rect = logical_rect.as_physical(Some(self.layout.containing_block))
} });
fragment fragment
}) })
@ -436,7 +436,7 @@ impl LineItemLayout<'_, '_> {
.into_iter() .into_iter()
.map(|(mut fragment, logical_rect)| { .map(|(mut fragment, logical_rect)| {
let is_float = matches!(fragment, Fragment::Float(_)); let is_float = matches!(fragment, Fragment::Float(_));
if let Some(content_rect) = fragment.content_rect_mut() { fragment.mutate_content_rect(|content_rect| {
if is_float { if is_float {
content_rect.origin -= content_rect.origin -=
pbm_sums.start_offset().to_physical_size(ifc_writing_mode); pbm_sums.start_offset().to_physical_size(ifc_writing_mode);
@ -446,7 +446,7 @@ impl LineItemLayout<'_, '_> {
// into a physical one now that we've computed inline size of the containing inline block above. // into a physical one now that we've computed inline size of the containing inline block above.
*content_rect = logical_rect.as_physical(Some(&inline_box_containing_block)) *content_rect = logical_rect.as_physical(Some(&inline_box_containing_block))
} }
} });
fragment fragment
}) })
.collect(); .collect();
@ -495,7 +495,7 @@ impl LineItemLayout<'_, '_> {
self.current_state.inline_advance += inner_state.inline_advance + pbm_sums.inline_sum(); self.current_state.inline_advance += inner_state.inline_advance + pbm_sums.inline_sum();
self.current_state self.current_state
.fragments .fragments
.push((Fragment::Box(fragment), content_rect)); .push((Fragment::Box(ArcRefCell::new(fragment)), content_rect));
} }
fn calculate_inline_box_block_start( fn calculate_inline_box_block_start(
@ -566,7 +566,7 @@ impl LineItemLayout<'_, '_> {
self.current_state.inline_advance += inline_advance; self.current_state.inline_advance += inline_advance;
self.current_state.fragments.push(( self.current_state.fragments.push((
Fragment::Text(TextFragment { Fragment::Text(ArcRefCell::new(TextFragment {
base: text_item.base_fragment_info.into(), base: text_item.base_fragment_info.into(),
parent_style: text_item.parent_style, parent_style: text_item.parent_style,
rect: PhysicalRect::zero(), rect: PhysicalRect::zero(),
@ -575,7 +575,7 @@ impl LineItemLayout<'_, '_> {
glyphs: text_item.text, glyphs: text_item.text,
text_decoration_line: text_item.text_decoration_line, text_decoration_line: text_item.text_decoration_line,
justification_adjustment: self.justification_adjustment, justification_adjustment: self.justification_adjustment,
}), })),
content_rect, content_rect,
)); ));
} }
@ -627,9 +627,10 @@ impl LineItemLayout<'_, '_> {
} }
self.current_state.inline_advance += atomic.size.inline; self.current_state.inline_advance += atomic.size.inline;
self.current_state self.current_state.fragments.push((
.fragments Fragment::Box(ArcRefCell::new(atomic.fragment)),
.push((Fragment::Box(atomic.fragment), content_rect)); content_rect,
));
} }
fn layout_absolute(&mut self, absolute: AbsolutelyPositionedLineItem) { fn layout_absolute(&mut self, absolute: AbsolutelyPositionedLineItem) {
@ -706,9 +707,10 @@ impl LineItemLayout<'_, '_> {
float.fragment.content_rect.origin -= distance_from_parent_to_ifc float.fragment.content_rect.origin -= distance_from_parent_to_ifc
.to_physical_size(self.layout.containing_block.style.writing_mode); .to_physical_size(self.layout.containing_block.style.writing_mode);
self.current_state self.current_state.fragments.push((
.fragments Fragment::Float(ArcRefCell::new(float.fragment)),
.push((Fragment::Float(float.fragment), LogicalRect::zero())); LogicalRect::zero(),
));
} }
} }

View file

@ -289,9 +289,9 @@ impl OutsideMarker {
.fold(Au::zero(), |current_max, fragment| { .fold(Au::zero(), |current_max, fragment| {
current_max.max( current_max.max(
match fragment { match fragment {
Fragment::Text(text) => text.rect, Fragment::Text(text) => text.borrow().rect,
Fragment::Image(image) => image.rect, Fragment::Image(image) => image.borrow().rect,
Fragment::Positioning(positioning) => positioning.rect, Fragment::Positioning(positioning) => positioning.borrow().rect,
Fragment::Box(_) | Fragment::Box(_) |
Fragment::Float(_) | Fragment::Float(_) |
Fragment::AbsoluteOrFixedPositioned(_) | Fragment::AbsoluteOrFixedPositioned(_) |
@ -331,7 +331,7 @@ impl OutsideMarker {
let mut base_fragment_info = BaseFragmentInfo::anonymous(); let mut base_fragment_info = BaseFragmentInfo::anonymous();
base_fragment_info.flags |= FragmentFlags::IS_OUTSIDE_LIST_ITEM_MARKER; base_fragment_info.flags |= FragmentFlags::IS_OUTSIDE_LIST_ITEM_MARKER;
Fragment::Box(BoxFragment::new( Fragment::Box(ArcRefCell::new(BoxFragment::new(
base_fragment_info, base_fragment_info,
self.marker_style.clone(), self.marker_style.clone(),
flow_layout.fragments, flow_layout.fragments,
@ -341,7 +341,7 @@ impl OutsideMarker {
PhysicalSides::zero(), PhysicalSides::zero(),
None, None,
CollapsedBlockMargins::zero(), CollapsedBlockMargins::zero(),
)) )))
} }
} }
@ -724,8 +724,8 @@ impl BlockLevelBox {
collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>, collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>,
) -> Fragment { ) -> Fragment {
match self { match self {
BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => { BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => Fragment::Box(
Fragment::Box(positioning_context.layout_maybe_position_relative_fragment( ArcRefCell::new(positioning_context.layout_maybe_position_relative_fragment(
layout_context, layout_context,
containing_block, containing_block,
&base.style, &base.style,
@ -740,10 +740,10 @@ impl BlockLevelBox {
collapsible_with_parent_start_margin, collapsible_with_parent_start_margin,
) )
}, },
)) )),
}, ),
BlockLevelBox::Independent(independent) => { BlockLevelBox::Independent(independent) => Fragment::Box(ArcRefCell::new(
Fragment::Box(positioning_context.layout_maybe_position_relative_fragment( positioning_context.layout_maybe_position_relative_fragment(
layout_context, layout_context,
containing_block, containing_block,
independent.style(), independent.style(),
@ -755,8 +755,8 @@ impl BlockLevelBox {
sequential_layout_state, sequential_layout_state,
) )
}, },
)) ),
}, )),
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
// The static position of zero here is incorrect, however we do not know // The static position of zero here is incorrect, however we do not know
// the correct positioning until later, in place_block_level_fragment, and // the correct positioning until later, in place_block_level_fragment, and
@ -777,10 +777,8 @@ impl BlockLevelBox {
positioning_context.push(hoisted_box); positioning_context.push(hoisted_box);
Fragment::AbsoluteOrFixedPositioned(hoisted_fragment) Fragment::AbsoluteOrFixedPositioned(hoisted_fragment)
}, },
BlockLevelBox::OutOfFlowFloatBox(float_box) => Fragment::Float(float_box.layout( BlockLevelBox::OutOfFlowFloatBox(float_box) => Fragment::Float(ArcRefCell::new(
layout_context, float_box.layout(layout_context, positioning_context, containing_block),
positioning_context,
containing_block,
)), )),
BlockLevelBox::OutsideMarker(outside_marker) => outside_marker.layout( BlockLevelBox::OutsideMarker(outside_marker) => outside_marker.layout(
layout_context, layout_context,
@ -1912,6 +1910,7 @@ impl<'container> PlacementState<'container> {
Fragment::Box(box_fragment) => box_fragment, Fragment::Box(box_fragment) => box_fragment,
_ => return, _ => return,
}; };
let box_fragment = box_fragment.borrow();
// From <https://drafts.csswg.org/css-align-3/#baseline-export>: // From <https://drafts.csswg.org/css-align-3/#baseline-export>:
// > When finding the first/last baseline set of an inline-block, any baselines // > When finding the first/last baseline set of an inline-block, any baselines
@ -1955,6 +1954,7 @@ impl<'container> PlacementState<'container> {
// between the marker and the item. For instance the marker should be positioned at // between the marker and the item. For instance the marker should be positioned at
// the baseline of list item content and the first line of the item content should // the baseline of list item content and the first line of the item content should
// be at least as tall as the marker -- not the entire list item itself. // be at least as tall as the marker -- not the entire list item itself.
let fragment = &mut *fragment.borrow_mut();
let is_outside_marker = fragment let is_outside_marker = fragment
.base .base
.flags .flags
@ -2049,6 +2049,7 @@ impl<'container> PlacementState<'container> {
.expect("Found float fragment without SequentialLayoutState"); .expect("Found float fragment without SequentialLayoutState");
let block_offset_from_containing_block_top = let block_offset_from_containing_block_top =
self.current_block_direction_position + self.current_margin.solve(); self.current_block_direction_position + self.current_margin.solve();
let box_fragment = &mut *box_fragment.borrow_mut();
sequential_layout_state.place_float_fragment( sequential_layout_state.place_float_fragment(
box_fragment, box_fragment,
self.containing_block, self.containing_block,

View file

@ -357,11 +357,7 @@ impl BoxTree {
&(&initial_containing_block).into(), &(&initial_containing_block).into(),
); );
let mut root_fragments = independent_layout let mut root_fragments = independent_layout.fragments.into_iter().collect::<Vec<_>>();
.fragments
.into_iter()
.map(ArcRefCell::new)
.collect::<Vec<_>>();
// Zero box for `:root { display: none }`, one for the root element otherwise. // Zero box for `:root { display: none }`, one for the root element otherwise.
assert!(root_fragments.len() <= 1); assert!(root_fragments.len() <= 1);
@ -378,7 +374,7 @@ impl BoxTree {
let scrollable_overflow = root_fragments let scrollable_overflow = root_fragments
.iter() .iter()
.fold(PhysicalRect::zero(), |acc, child| { .fold(PhysicalRect::zero(), |acc, child| {
let child_overflow = child.borrow().scrollable_overflow(); let child_overflow = child.scrollable_overflow();
// https://drafts.csswg.org/css-overflow/#scrolling-direction // https://drafts.csswg.org/css-overflow/#scrolling-direction
// We want to clip scrollable overflow on box-start and inline-start // We want to clip scrollable overflow on box-start and inline-start

View file

@ -13,7 +13,7 @@ use crate::layout_debug::DebugId;
/// This data structure stores fields that are common to all non-base /// This data structure stores fields that are common to all non-base
/// Fragment types and should generally be the first member of all /// Fragment types and should generally be the first member of all
/// concrete fragments. /// concrete fragments.
#[derive(Debug, Serialize)] #[derive(Clone, Debug, Serialize)]
pub(crate) struct BaseFragment { pub(crate) struct BaseFragment {
/// A tag which identifies the DOM node and pseudo element of this /// A tag which identifies the DOM node and pseudo element of this
/// Fragment's content. If this fragment isn't related to any DOM /// Fragment's content. If this fragment isn't related to any DOM

View file

@ -3,6 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use app_units::Au; use app_units::Au;
use atomic_refcell::AtomicRefCell;
use base::print_tree::PrintTree; use base::print_tree::PrintTree;
use serde::Serialize; use serde::Serialize;
use servo_arc::Arc as ServoArc; use servo_arc::Arc as ServoArc;
@ -13,7 +14,6 @@ use style::properties::ComputedValues;
use style::Zero; use style::Zero;
use super::{BaseFragment, BaseFragmentInfo, CollapsedBlockMargins, Fragment}; use super::{BaseFragment, BaseFragmentInfo, CollapsedBlockMargins, Fragment};
use crate::cell::ArcRefCell;
use crate::formatting_contexts::Baselines; use crate::formatting_contexts::Baselines;
use crate::fragment_tree::FragmentFlags; use crate::fragment_tree::FragmentFlags;
use crate::geom::{ use crate::geom::{
@ -53,7 +53,7 @@ pub(crate) struct BoxFragment {
#[serde(skip_serializing)] #[serde(skip_serializing)]
pub style: ServoArc<ComputedValues>, 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 /// 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. /// 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 /// 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 /// during stacking context tree construction because they rely on the size of the
/// scroll container. /// 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)] #[serde(skip_serializing)]
pub background_mode: BackgroundMode, pub background_mode: BackgroundMode,
@ -115,7 +116,7 @@ impl BoxFragment {
BoxFragment { BoxFragment {
base: base_fragment_info.into(), base: base_fragment_info.into(),
style, style,
children: children.into_iter().map(ArcRefCell::new).collect(), children,
content_rect, content_rect,
padding, padding,
border, border,
@ -124,7 +125,7 @@ impl BoxFragment {
baselines: Baselines::default(), baselines: Baselines::default(),
block_margins_collapsed_with_children, block_margins_collapsed_with_children,
scrollable_overflow_from_children, scrollable_overflow_from_children,
resolved_sticky_insets: None, resolved_sticky_insets: AtomicRefCell::default(),
background_mode: BackgroundMode::Normal, background_mode: BackgroundMode::Normal,
detailed_layout_info: None, detailed_layout_info: None,
} }
@ -234,7 +235,7 @@ impl BoxFragment {
)); ));
for child in &self.children { for child in &self.children {
child.borrow().print(tree); child.print(tree);
} }
tree.end_level(); tree.end_level();
} }
@ -278,7 +279,7 @@ impl BoxFragment {
"Should not call this method on statically positioned box." "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; return resolved_sticky_insets;
} }

View file

@ -52,7 +52,7 @@ pub(crate) struct ContainingBlockManager<'a, T> {
impl<'a, T> ContainingBlockManager<'a, T> { impl<'a, T> ContainingBlockManager<'a, T> {
pub(crate) fn get_containing_block_for_fragment(&self, fragment: &Fragment) -> &T { pub(crate) fn get_containing_block_for_fragment(&self, fragment: &Fragment) -> &T {
if let Fragment::Box(box_fragment) = fragment { 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::Fixed => self.for_absolute_and_fixed_descendants,
ComputedPosition::Absolute => self ComputedPosition::Absolute => self
.for_absolute_descendants .for_absolute_descendants

View file

@ -23,16 +23,16 @@ use crate::cell::ArcRefCell;
use crate::geom::{LogicalSides, PhysicalRect}; use crate::geom::{LogicalSides, PhysicalRect};
use crate::style_ext::ComputedValuesExt; use crate::style_ext::ComputedValuesExt;
#[derive(Serialize)] #[derive(Clone, Serialize)]
pub(crate) enum Fragment { pub(crate) enum Fragment {
Box(BoxFragment), Box(ArcRefCell<BoxFragment>),
/// Floating content. A floated fragment is very similar to a normal /// Floating content. A floated fragment is very similar to a normal
/// [BoxFragment] but it isn't positioned using normal in block flow /// [BoxFragment] but it isn't positioned using normal in block flow
/// positioning rules (margin collapse, etc). Instead, they are laid /// positioning rules (margin collapse, etc). Instead, they are laid
/// out by the [crate::flow::float::SequentialLayoutState] of their /// out by the [crate::flow::float::SequentialLayoutState] of their
/// float containing block formatting context. /// float containing block formatting context.
Float(BoxFragment), Float(ArcRefCell<BoxFragment>),
Positioning(PositioningFragment), Positioning(ArcRefCell<PositioningFragment>),
/// Absolute and fixed position fragments are hoisted up so that they /// Absolute and fixed position fragments are hoisted up so that they
/// are children of the BoxFragment that establishes their containing /// are children of the BoxFragment that establishes their containing
/// blocks, so that they can be laid out properly. When this happens /// 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 / /// regard to their original tree order during stacking context tree /
/// display list construction. /// display list construction.
AbsoluteOrFixedPositioned(ArcRefCell<HoistedSharedFragment>), AbsoluteOrFixedPositioned(ArcRefCell<HoistedSharedFragment>),
Text(TextFragment), Text(ArcRefCell<TextFragment>),
Image(ImageFragment), Image(ArcRefCell<ImageFragment>),
IFrame(IFrameFragment), IFrame(ArcRefCell<IFrameFragment>),
} }
#[derive(Serialize)] #[derive(Serialize)]
@ -99,26 +99,26 @@ pub(crate) struct IFrameFragment {
} }
impl Fragment { impl Fragment {
pub fn base(&self) -> Option<&BaseFragment> { pub fn base(&self) -> Option<BaseFragment> {
Some(match self { Some(match self {
Fragment::Box(fragment) => &fragment.base, Fragment::Box(fragment) => fragment.borrow().base.clone(),
Fragment::Text(fragment) => &fragment.base, Fragment::Text(fragment) => fragment.borrow().base.clone(),
Fragment::AbsoluteOrFixedPositioned(_) => return None, Fragment::AbsoluteOrFixedPositioned(_) => return None,
Fragment::Positioning(fragment) => &fragment.base, Fragment::Positioning(fragment) => fragment.borrow().base.clone(),
Fragment::Image(fragment) => &fragment.base, Fragment::Image(fragment) => fragment.borrow().base.clone(),
Fragment::IFrame(fragment) => &fragment.base, Fragment::IFrame(fragment) => fragment.borrow().base.clone(),
Fragment::Float(fragment) => &fragment.base, 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 { match self {
Fragment::Box(box_fragment) | Fragment::Float(box_fragment) => { 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::Positioning(_) | Fragment::AbsoluteOrFixedPositioned(_) => {},
Fragment::Text(text_fragment) => Some(&mut text_fragment.rect), Fragment::Text(text_fragment) => callback(&mut text_fragment.borrow_mut().rect),
Fragment::Image(image_fragment) => Some(&mut image_fragment.rect), Fragment::Image(image_fragment) => callback(&mut image_fragment.borrow_mut().rect),
Fragment::IFrame(iframe_fragment) => Some(&mut iframe_fragment.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) { pub fn print(&self, tree: &mut PrintTree) {
match self { match self {
Fragment::Box(fragment) => fragment.print(tree), Fragment::Box(fragment) => fragment.borrow().print(tree),
Fragment::Float(fragment) => { Fragment::Float(fragment) => {
tree.new_level("Float".to_string()); tree.new_level("Float".to_string());
fragment.print(tree); fragment.borrow().print(tree);
tree.end_level(); tree.end_level();
}, },
Fragment::AbsoluteOrFixedPositioned(_) => { Fragment::AbsoluteOrFixedPositioned(_) => {
tree.add_item("AbsoluteOrFixedPositioned".to_string()); tree.add_item("AbsoluteOrFixedPositioned".to_string());
}, },
Fragment::Positioning(fragment) => fragment.print(tree), Fragment::Positioning(fragment) => fragment.borrow().print(tree),
Fragment::Text(fragment) => fragment.print(tree), Fragment::Text(fragment) => fragment.borrow().print(tree),
Fragment::Image(fragment) => fragment.print(tree), Fragment::Image(fragment) => fragment.borrow().print(tree),
Fragment::IFrame(fragment) => fragment.print(tree), Fragment::IFrame(fragment) => fragment.borrow().print(tree),
} }
} }
pub fn scrolling_area(&self, containing_block: &PhysicalRect<Au>) -> PhysicalRect<Au> { pub fn scrolling_area(&self, containing_block: &PhysicalRect<Au>) -> PhysicalRect<Au> {
match self { match self {
Fragment::Box(fragment) | Fragment::Float(fragment) => fragment Fragment::Box(fragment) | Fragment::Float(fragment) => fragment
.borrow()
.scrollable_overflow() .scrollable_overflow()
.translate(containing_block.origin.to_vector()), .translate(containing_block.origin.to_vector()),
_ => self.scrollable_overflow(), _ => self.scrollable_overflow(),
@ -156,13 +157,13 @@ impl Fragment {
pub fn scrollable_overflow(&self) -> PhysicalRect<Au> { pub fn scrollable_overflow(&self) -> PhysicalRect<Au> {
match self { match self {
Fragment::Box(fragment) | Fragment::Float(fragment) => { Fragment::Box(fragment) | Fragment::Float(fragment) => {
fragment.scrollable_overflow_for_parent() fragment.borrow().scrollable_overflow_for_parent()
}, },
Fragment::AbsoluteOrFixedPositioned(_) => PhysicalRect::zero(), Fragment::AbsoluteOrFixedPositioned(_) => PhysicalRect::zero(),
Fragment::Positioning(fragment) => fragment.scrollable_overflow, Fragment::Positioning(fragment) => fragment.borrow().scrollable_overflow,
Fragment::Text(fragment) => fragment.rect, Fragment::Text(fragment) => fragment.borrow().rect,
Fragment::Image(fragment) => fragment.rect, Fragment::Image(fragment) => fragment.borrow().rect,
Fragment::IFrame(fragment) => fragment.rect, Fragment::IFrame(fragment) => fragment.borrow().rect,
} }
} }
@ -179,6 +180,7 @@ impl Fragment {
match self { match self {
Fragment::Box(fragment) | Fragment::Float(fragment) => { Fragment::Box(fragment) | Fragment::Float(fragment) => {
let fragment = fragment.borrow();
let content_rect = fragment let content_rect = fragment
.content_rect .content_rect
.translate(containing_block.origin.to_vector()); .translate(containing_block.origin.to_vector());
@ -202,15 +204,16 @@ impl Fragment {
fragment fragment
.children .children
.iter() .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) => { Fragment::Positioning(fragment) => {
let fragment = fragment.borrow();
let content_rect = fragment.rect.translate(containing_block.origin.to_vector()); let content_rect = fragment.rect.translate(containing_block.origin.to_vector());
let new_manager = manager.new_for_non_absolute_descendants(&content_rect); let new_manager = manager.new_for_non_absolute_descendants(&content_rect);
fragment fragment
.children .children
.iter() .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, _ => None,
} }

View file

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

View file

@ -8,7 +8,6 @@ use style::logical_geometry::WritingMode;
use style::values::specified::align::AlignFlags; use style::values::specified::align::AlignFlags;
use super::Fragment; use super::Fragment;
use crate::cell::ArcRefCell;
use crate::geom::{LogicalVec2, PhysicalRect, PhysicalVec}; use crate::geom::{LogicalVec2, PhysicalRect, PhysicalVec};
/// A reference to a Fragment which is shared between `HoistedAbsolutelyPositionedBox` /// 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. /// This will be used later in order to paint this hoisted box in tree order.
#[derive(Serialize)] #[derive(Serialize)]
pub(crate) struct HoistedSharedFragment { 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 /// The "static-position rect" of this absolutely positioned box. This is defined by the
/// layout mode from which the box originates. /// layout mode from which the box originates.
/// ///

View file

@ -19,7 +19,7 @@ use crate::geom::PhysicalRect;
pub(crate) struct PositioningFragment { pub(crate) struct PositioningFragment {
pub base: BaseFragment, pub base: BaseFragment,
pub rect: PhysicalRect<Au>, pub rect: PhysicalRect<Au>,
pub children: Vec<ArcRefCell<Fragment>>, pub children: Vec<Fragment>,
/// The scrollable overflow of this anonymous fragment's children. /// The scrollable overflow of this anonymous fragment's children.
pub scrollable_overflow: PhysicalRect<Au>, pub scrollable_overflow: PhysicalRect<Au>,
@ -29,7 +29,7 @@ pub(crate) struct PositioningFragment {
} }
impl 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) Self::new_with_base_fragment(BaseFragment::anonymous(), None, rect, children)
} }
@ -37,7 +37,7 @@ impl PositioningFragment {
base_fragment_info: BaseFragmentInfo, base_fragment_info: BaseFragmentInfo,
rect: PhysicalRect<Au>, rect: PhysicalRect<Au>,
style: ServoArc<ComputedValues>, style: ServoArc<ComputedValues>,
) -> Self { ) -> ArcRefCell<Self> {
Self::new_with_base_fragment(base_fragment_info.into(), Some(style), rect, Vec::new()) Self::new_with_base_fragment(base_fragment_info.into(), Some(style), rect, Vec::new())
} }
@ -46,7 +46,7 @@ impl PositioningFragment {
style: Option<ServoArc<ComputedValues>>, style: Option<ServoArc<ComputedValues>>,
rect: PhysicalRect<Au>, rect: PhysicalRect<Au>,
children: Vec<Fragment>, children: Vec<Fragment>,
) -> Self { ) -> ArcRefCell<Self> {
let content_origin = rect.origin; let content_origin = rect.origin;
let scrollable_overflow = children.iter().fold(PhysicalRect::zero(), |acc, child| { let scrollable_overflow = children.iter().fold(PhysicalRect::zero(), |acc, child| {
acc.union( acc.union(
@ -55,13 +55,13 @@ impl PositioningFragment {
.translate(content_origin.to_vector()), .translate(content_origin.to_vector()),
) )
}); });
PositioningFragment { ArcRefCell::new(PositioningFragment {
base, base,
style, style,
rect, rect,
children: children.into_iter().map(ArcRefCell::new).collect(), children,
scrollable_overflow, scrollable_overflow,
} })
} }
pub fn print(&self, tree: &mut PrintTree) { pub fn print(&self, tree: &mut PrintTree) {
@ -74,7 +74,7 @@ impl PositioningFragment {
)); ));
for child in &self.children { for child in &self.children {
child.borrow().print(tree); child.print(tree);
} }
tree.end_level(); tree.end_level();
} }

View file

@ -161,9 +161,11 @@ impl PositioningContext {
index: PositioningContextLength, index: PositioningContextLength,
) { ) {
let start_offset = match &parent_fragment { let start_offset = match &parent_fragment {
Fragment::Box(fragment) | Fragment::Float(fragment) => &fragment.content_rect.origin, Fragment::Box(fragment) | Fragment::Float(fragment) => {
fragment.borrow().content_rect.origin
},
Fragment::AbsoluteOrFixedPositioned(_) => return, Fragment::AbsoluteOrFixedPositioned(_) => return,
Fragment::Positioning(fragment) => &fragment.rect.origin, Fragment::Positioning(fragment) => fragment.borrow().rect.origin,
_ => unreachable!(), _ => unreachable!(),
}; };
self.adjust_static_position_of_hoisted_fragments_with_offset( self.adjust_static_position_of_hoisted_fragments_with_offset(
@ -335,7 +337,7 @@ impl PositioningContext {
&mut self, &mut self,
layout_context: &LayoutContext, layout_context: &LayoutContext,
initial_containing_block: &DefiniteContainingBlock, initial_containing_block: &DefiniteContainingBlock,
fragments: &mut Vec<ArcRefCell<Fragment>>, fragments: &mut Vec<Fragment>,
) { ) {
debug_assert!(self.for_nearest_positioned_ancestor.is_none()); debug_assert!(self.for_nearest_positioned_ancestor.is_none());
@ -409,7 +411,7 @@ impl HoistedAbsolutelyPositionedBox {
pub(crate) fn layout_many( pub(crate) fn layout_many(
layout_context: &LayoutContext, layout_context: &LayoutContext,
boxes: &mut [Self], boxes: &mut [Self],
fragments: &mut Vec<ArcRefCell<Fragment>>, fragments: &mut Vec<Fragment>,
for_nearest_containing_block_for_all_descendants: &mut Vec<HoistedAbsolutelyPositionedBox>, for_nearest_containing_block_for_all_descendants: &mut Vec<HoistedAbsolutelyPositionedBox>,
containing_block: &DefiniteContainingBlock, containing_block: &DefiniteContainingBlock,
) { ) {
@ -421,14 +423,15 @@ impl HoistedAbsolutelyPositionedBox {
.par_iter_mut() .par_iter_mut()
.map(|hoisted_box| { .map(|hoisted_box| {
let mut new_hoisted_boxes: Vec<HoistedAbsolutelyPositionedBox> = Vec::new(); let mut new_hoisted_boxes: Vec<HoistedAbsolutelyPositionedBox> = Vec::new();
let new_fragment = ArcRefCell::new(Fragment::Box(hoisted_box.layout( let new_fragment = hoisted_box.layout(
layout_context, layout_context,
&mut new_hoisted_boxes, &mut new_hoisted_boxes,
containing_block, containing_block,
))); );
hoisted_box.fragment.borrow_mut().fragment = Some(new_fragment.clone()); hoisted_box.fragment.borrow_mut().fragment =
(new_fragment, new_hoisted_boxes) Some(Fragment::Box(new_fragment.clone()));
(Fragment::Box(new_fragment), new_hoisted_boxes)
}) })
.unzip_into_vecs(&mut new_fragments, &mut new_hoisted_boxes); .unzip_into_vecs(&mut new_fragments, &mut new_hoisted_boxes);
@ -437,13 +440,14 @@ impl HoistedAbsolutelyPositionedBox {
.extend(new_hoisted_boxes.into_iter().flatten()); .extend(new_hoisted_boxes.into_iter().flatten());
} else { } else {
fragments.extend(boxes.iter_mut().map(|box_| { fragments.extend(boxes.iter_mut().map(|box_| {
let new_fragment = ArcRefCell::new(Fragment::Box(box_.layout( let new_fragment = box_.layout(
layout_context, layout_context,
for_nearest_containing_block_for_all_descendants, for_nearest_containing_block_for_all_descendants,
containing_block, containing_block,
))); );
box_.fragment.borrow_mut().fragment = Some(new_fragment.clone());
new_fragment box_.fragment.borrow_mut().fragment = Some(Fragment::Box(new_fragment.clone()));
Fragment::Box(new_fragment)
})) }))
} }
} }
@ -453,7 +457,7 @@ impl HoistedAbsolutelyPositionedBox {
layout_context: &LayoutContext, layout_context: &LayoutContext,
for_nearest_containing_block_for_all_descendants: &mut Vec<HoistedAbsolutelyPositionedBox>, for_nearest_containing_block_for_all_descendants: &mut Vec<HoistedAbsolutelyPositionedBox>,
containing_block: &DefiniteContainingBlock, containing_block: &DefiniteContainingBlock,
) -> BoxFragment { ) -> ArcRefCell<BoxFragment> {
let cbis = containing_block.size.inline; let cbis = containing_block.size.inline;
let cbbs = containing_block.size.block; let cbbs = containing_block.size.block;
let containing_block_writing_mode = containing_block.style.writing_mode; let containing_block_writing_mode = containing_block.style.writing_mode;
@ -696,7 +700,7 @@ impl HoistedAbsolutelyPositionedBox {
for_nearest_containing_block_for_all_descendants for_nearest_containing_block_for_all_descendants
.extend(positioning_context.for_nearest_containing_block_for_all_descendants); .extend(positioning_context.for_nearest_containing_block_for_all_descendants);
new_fragment ArcRefCell::new(new_fragment)
} }
} }

View file

@ -192,6 +192,7 @@ pub fn process_resolved_style_request<'dom>(
let (content_rect, margins, padding, detailed_layout_info) = match fragment { let (content_rect, margins, padding, detailed_layout_info) = match fragment {
Fragment::Box(ref box_fragment) | Fragment::Float(ref box_fragment) => { Fragment::Box(ref box_fragment) | Fragment::Float(ref box_fragment) => {
let box_fragment = box_fragment.borrow();
if style.get_box().position != Position::Static { if style.get_box().position != Position::Static {
let resolved_insets = || { let resolved_insets = || {
box_fragment.calculate_resolved_insets_if_positioned(containing_block) box_fragment.calculate_resolved_insets_if_positioned(containing_block)
@ -213,16 +214,16 @@ pub fn process_resolved_style_request<'dom>(
let content_rect = box_fragment.content_rect; let content_rect = box_fragment.content_rect;
let margins = box_fragment.margin; let margins = box_fragment.margin;
let padding = box_fragment.padding; let padding = box_fragment.padding;
let detailed_layout_info = &box_fragment.detailed_layout_info; let detailed_layout_info = box_fragment.detailed_layout_info.clone();
(content_rect, margins, padding, detailed_layout_info) (content_rect, margins, padding, detailed_layout_info)
}, },
Fragment::Positioning(positioning_fragment) => { Fragment::Positioning(positioning_fragment) => {
let content_rect = positioning_fragment.rect; let content_rect = positioning_fragment.borrow().rect;
( (
content_rect, content_rect,
SideOffsets2D::zero(), SideOffsets2D::zero(),
SideOffsets2D::zero(), SideOffsets2D::zero(),
&None, None,
) )
}, },
_ => return None, _ => return None,
@ -235,7 +236,7 @@ pub fn process_resolved_style_request<'dom>(
// > When an element generates a grid container box... // > When an element generates a grid container box...
if display.inside() == DisplayInside::Grid { if display.inside() == DisplayInside::Grid {
if let Some(SpecificLayoutInfo::Grid(info)) = detailed_layout_info { if let Some(SpecificLayoutInfo::Grid(info)) = detailed_layout_info {
if let Some(value) = resolve_grid_template(info, style, longhand_id) { if let Some(value) = resolve_grid_template(&info, style, longhand_id) {
return Some(value); return Some(value);
} }
} }
@ -274,7 +275,7 @@ fn resolved_size_should_be_used_value(fragment: &Fragment) -> bool {
// https://drafts.csswg.org/css-sizing-3/#preferred-size-properties // https://drafts.csswg.org/css-sizing-3/#preferred-size-properties
// > Applies to: all elements except non-replaced inlines // > Applies to: all elements except non-replaced inlines
match fragment { match fragment {
Fragment::Box(box_fragment) => !box_fragment.is_inline_box(), Fragment::Box(box_fragment) => !box_fragment.borrow().is_inline_box(),
Fragment::Float(_) | Fragment::Float(_) |
Fragment::Positioning(_) | Fragment::Positioning(_) |
Fragment::AbsoluteOrFixedPositioned(_) | Fragment::AbsoluteOrFixedPositioned(_) |
@ -446,9 +447,9 @@ fn process_offset_parent_query_inner(
// //
// [1]: https://github.com/w3c/csswg-drafts/issues/4541 // [1]: https://github.com/w3c/csswg-drafts/issues/4541
let fragment_relative_rect = match fragment { let fragment_relative_rect = match fragment {
Fragment::Box(fragment) | Fragment::Float(fragment) => fragment.border_rect(), Fragment::Box(fragment) | Fragment::Float(fragment) => fragment.borrow().border_rect(),
Fragment::Text(fragment) => fragment.rect, Fragment::Text(fragment) => fragment.borrow().rect,
Fragment::Positioning(fragment) => fragment.rect, Fragment::Positioning(fragment) => fragment.borrow().rect,
Fragment::AbsoluteOrFixedPositioned(_) | Fragment::AbsoluteOrFixedPositioned(_) |
Fragment::Image(_) | Fragment::Image(_) |
Fragment::IFrame(_) => unreachable!(), Fragment::IFrame(_) => unreachable!(),
@ -460,7 +461,7 @@ fn process_offset_parent_query_inner(
// this algorithm: [...] The elements computed value of the // this algorithm: [...] The elements computed value of the
// `position` property is `fixed`." // `position` property is `fixed`."
let is_fixed = matches!( let is_fixed = matches!(
fragment, Fragment::Box(fragment) if fragment.style.get_box().position == Position::Fixed fragment, Fragment::Box(fragment) if fragment.borrow().style.get_box().position == Position::Fixed
); );
if is_body_element { if is_body_element {
@ -489,6 +490,7 @@ fn process_offset_parent_query_inner(
// Record the paths of the nodes being traversed. // Record the paths of the nodes being traversed.
let parent_node_address = match fragment { let parent_node_address = match fragment {
Fragment::Box(fragment) | Fragment::Float(fragment) => { Fragment::Box(fragment) | Fragment::Float(fragment) => {
let fragment = &*fragment.borrow();
let is_eligible_parent = is_eligible_parent(fragment); let is_eligible_parent = is_eligible_parent(fragment);
let is_static_body_element = is_body_element && let is_static_body_element = is_body_element &&
fragment.style.get_box().position == Position::Static; fragment.style.get_box().position == Position::Static;
@ -538,14 +540,15 @@ fn process_offset_parent_query_inner(
unreachable!(); unreachable!();
}; };
// Again, take the *first* associated CSS layout box. // Again, take the *first* associated CSS layout box.
fragment.border_rect().origin.to_vector() + containing_block.origin.to_vector() fragment.borrow().border_rect().origin.to_vector() +
containing_block.origin.to_vector()
} }
let containing_block = &fragment_tree.initial_containing_block; let containing_block = &fragment_tree.initial_containing_block;
let fragment = &(*fragment_tree.root_fragments[0].borrow()); let fragment = &fragment_tree.root_fragments[0];
if let Fragment::AbsoluteOrFixedPositioned(shared_fragment) = fragment { if let Fragment::AbsoluteOrFixedPositioned(shared_fragment) = fragment {
let shared_fragment = &*shared_fragment.borrow(); let shared_fragment = &*shared_fragment.borrow();
let fragment = &*shared_fragment.fragment.as_ref().unwrap().borrow(); let fragment = shared_fragment.fragment.as_ref().unwrap();
extract_box_fragment(fragment, containing_block) extract_box_fragment(fragment, containing_block)
} else { } else {
extract_box_fragment(fragment, containing_block) extract_box_fragment(fragment, containing_block)
@ -561,6 +564,7 @@ fn process_offset_parent_query_inner(
.find(|fragment, _, containing_block| { .find(|fragment, _, containing_block| {
match fragment { match fragment {
Fragment::Box(fragment) | Fragment::Float(fragment) => { Fragment::Box(fragment) | Fragment::Float(fragment) => {
let fragment = fragment.borrow();
if fragment.base.tag == Some(offset_parent_node_tag) { if fragment.base.tag == Some(offset_parent_node_tag) {
// Again, take the *first* associated CSS layout box. // Again, take the *first* associated CSS layout box.
let padding_box_corner = fragment.padding_rect().origin.to_vector() let padding_box_corner = fragment.padding_rect().origin.to_vector()

View file

@ -27,6 +27,7 @@ use style::Zero;
use url::Url; use url::Url;
use webrender_api::ImageKey; use webrender_api::ImageKey;
use crate::cell::ArcRefCell;
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::dom::NodeExt; use crate::dom::NodeExt;
use crate::fragment_tree::{BaseFragmentInfo, Fragment, IFrameFragment, ImageFragment}; use crate::fragment_tree::{BaseFragmentInfo, Fragment, IFrameFragment, ImageFragment};
@ -334,23 +335,25 @@ impl ReplacedContents {
.as_ref() .as_ref()
.and_then(|image| image.id) .and_then(|image| image.id)
.map(|image_key| { .map(|image_key| {
Fragment::Image(ImageFragment { Fragment::Image(ArcRefCell::new(ImageFragment {
base: self.base_fragment_info.into(), base: self.base_fragment_info.into(),
style: style.clone(), style: style.clone(),
rect, rect,
clip, clip,
image_key: Some(image_key), image_key: Some(image_key),
}) }))
}) })
.into_iter() .into_iter()
.collect(), .collect(),
ReplacedContentKind::Video(video) => vec![Fragment::Image(ImageFragment { ReplacedContentKind::Video(video) => {
base: self.base_fragment_info.into(), vec![Fragment::Image(ArcRefCell::new(ImageFragment {
style: style.clone(), base: self.base_fragment_info.into(),
rect, style: style.clone(),
clip, rect,
image_key: video.as_ref().map(|video| video.image_key), clip,
})], image_key: video.as_ref().map(|video| video.image_key),
}))]
},
ReplacedContentKind::IFrame(iframe) => { ReplacedContentKind::IFrame(iframe) => {
let size = Size2D::new(rect.size.width.to_f32_px(), rect.size.height.to_f32_px()); let size = Size2D::new(rect.size.width.to_f32_px(), rect.size.height.to_f32_px());
layout_context.iframe_sizes.lock().insert( layout_context.iframe_sizes.lock().insert(
@ -361,13 +364,13 @@ impl ReplacedContents {
size, size,
}, },
); );
vec![Fragment::IFrame(IFrameFragment { vec![Fragment::IFrame(ArcRefCell::new(IFrameFragment {
base: self.base_fragment_info.into(), base: self.base_fragment_info.into(),
style: style.clone(), style: style.clone(),
pipeline_id: iframe.pipeline_id, pipeline_id: iframe.pipeline_id,
browsing_context_id: iframe.browsing_context_id, browsing_context_id: iframe.browsing_context_id,
rect, rect,
})] }))]
}, },
ReplacedContentKind::Canvas(canvas_info) => { ReplacedContentKind::Canvas(canvas_info) => {
if self.natural_size.width == Some(Au::zero()) || if self.natural_size.width == Some(Au::zero()) ||
@ -392,13 +395,13 @@ impl ReplacedContents {
}, },
CanvasSource::Empty => return vec![], CanvasSource::Empty => return vec![],
}; };
vec![Fragment::Image(ImageFragment { vec![Fragment::Image(ArcRefCell::new(ImageFragment {
base: self.base_fragment_info.into(), base: self.base_fragment_info.into(),
style: style.clone(), style: style.clone(),
rect, rect,
clip, clip,
image_key: Some(image_key), image_key: Some(image_key),
})] }))]
}, },
} }
} }

View file

@ -24,7 +24,9 @@ use style::values::generics::box_::{GenericVerticalAlign as VerticalAlign, Verti
use style::values::generics::length::GenericLengthPercentageOrAuto::{Auto, LengthPercentage}; use style::values::generics::length::GenericLengthPercentageOrAuto::{Auto, LengthPercentage};
use style::Zero; use style::Zero;
use super::{Table, TableCaption, TableSlot, TableSlotCell, TableTrack, TableTrackGroup}; use super::{
ArcRefCell, Table, TableCaption, TableSlot, TableSlotCell, TableTrack, TableTrackGroup,
};
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::formatting_contexts::{Baselines, IndependentLayout}; use crate::formatting_contexts::{Baselines, IndependentLayout};
use crate::fragment_tree::{ use crate::fragment_tree::{
@ -1740,7 +1742,7 @@ impl<'a> TableLayout<'a> {
.to_logical(table_writing_mode) .to_logical(table_writing_mode)
.block; .block;
let caption_fragment = Fragment::Box(caption_fragment); let caption_fragment = Fragment::Box(ArcRefCell::new(caption_fragment));
positioning_context.adjust_static_position_of_hoisted_fragments( positioning_context.adjust_static_position_of_hoisted_fragments(
&caption_fragment, &caption_fragment,
original_positioning_context_length, original_positioning_context_length,
@ -1790,7 +1792,7 @@ impl<'a> TableLayout<'a> {
.block; .block;
table_layout.content_inline_size_for_table = Some(logical_grid_content_rect.size.inline); table_layout.content_inline_size_for_table = Some(logical_grid_content_rect.size.inline);
let grid_fragment = Fragment::Box(grid_fragment); let grid_fragment = Fragment::Box(ArcRefCell::new(grid_fragment));
positioning_context.adjust_static_position_of_hoisted_fragments( positioning_context.adjust_static_position_of_hoisted_fragments(
&grid_fragment, &grid_fragment,
original_positioning_context_length, original_positioning_context_length,
@ -1831,7 +1833,7 @@ impl<'a> TableLayout<'a> {
.to_logical(table_writing_mode) .to_logical(table_writing_mode)
.block; .block;
let caption_fragment = Fragment::Box(caption_fragment); let caption_fragment = Fragment::Box(ArcRefCell::new(caption_fragment));
positioning_context.adjust_static_position_of_hoisted_fragments( positioning_context.adjust_static_position_of_hoisted_fragments(
&caption_fragment, &caption_fragment,
original_positioning_context_length, original_positioning_context_length,
@ -2182,7 +2184,9 @@ impl<'a> TableLayout<'a> {
rect, rect,
}) })
} }
row_fragment_layout.fragments.push(Fragment::Box(fragment)); row_fragment_layout
.fragments
.push(Fragment::Box(ArcRefCell::new(fragment)));
} }
fn make_fragments_for_columns_and_column_groups( fn make_fragments_for_columns_and_column_groups(
@ -2345,7 +2349,7 @@ impl<'a> RowFragmentLayout<'a> {
containing_block_for_logical_conversion: &ContainingBlock, containing_block_for_logical_conversion: &ContainingBlock,
containing_block_for_children: &ContainingBlock, containing_block_for_children: &ContainingBlock,
row_group_fragment_layout: &mut Option<RowGroupFragmentLayout>, row_group_fragment_layout: &mut Option<RowGroupFragmentLayout>,
) -> BoxFragment { ) -> ArcRefCell<BoxFragment> {
if self.positioning_context.is_some() { if self.positioning_context.is_some() {
self.rect.start_corner += self.rect.start_corner +=
relative_adjustement(&self.row.style, containing_block_for_children); relative_adjustement(&self.row.style, containing_block_for_children);
@ -2396,7 +2400,7 @@ impl<'a> RowFragmentLayout<'a> {
positioning_context.append(row_positioning_context); positioning_context.append(row_positioning_context);
} }
row_fragment ArcRefCell::new(row_fragment)
} }
} }
@ -2432,7 +2436,7 @@ impl RowGroupFragmentLayout {
table_positioning_context: &mut PositioningContext, table_positioning_context: &mut PositioningContext,
containing_block_for_logical_conversion: &ContainingBlock, containing_block_for_logical_conversion: &ContainingBlock,
containing_block_for_children: &ContainingBlock, containing_block_for_children: &ContainingBlock,
) -> BoxFragment { ) -> ArcRefCell<BoxFragment> {
if self.positioning_context.is_some() { if self.positioning_context.is_some() {
self.rect.start_corner += self.rect.start_corner +=
relative_adjustement(&self.style, containing_block_for_children); relative_adjustement(&self.style, containing_block_for_children);
@ -2458,7 +2462,7 @@ impl RowGroupFragmentLayout {
table_positioning_context.append(row_positioning_context); table_positioning_context.append(row_positioning_context);
} }
row_group_fragment ArcRefCell::new(row_group_fragment)
} }
} }

View file

@ -551,7 +551,7 @@ impl TaffyContainer {
match &mut child.taffy_level_box { match &mut child.taffy_level_box {
TaffyItemBoxInner::InFlowBox(independent_box) => { TaffyItemBoxInner::InFlowBox(independent_box) => {
let fragment = Fragment::Box( let fragment = Fragment::Box(ArcRefCell::new(
BoxFragment::new( BoxFragment::new(
independent_box.base_fragment_info(), independent_box.base_fragment_info(),
independent_box.style().clone(), independent_box.style().clone(),
@ -568,7 +568,7 @@ impl TaffyContainer {
last: None, last: None,
}) })
.with_detailed_layout_info(child_detailed_layout_info), .with_detailed_layout_info(child_detailed_layout_info),
); ));
child child
.positioning_context .positioning_context