diff --git a/components/layout_2020/cell.rs b/components/layout_2020/cell.rs index 910a6ab2104..d725362b0fa 100644 --- a/components/layout_2020/cell.rs +++ b/components/layout_2020/cell.rs @@ -8,7 +8,7 @@ use std::ops::Deref; use atomic_refcell::AtomicRefCell; use servo_arc::Arc; -pub(crate) struct ArcRefCell { +pub struct ArcRefCell { value: Arc>, } diff --git a/components/layout_2020/dom.rs b/components/layout_2020/dom.rs index 8ea718c4bec..c87c54d52ef 100644 --- a/components/layout_2020/dom.rs +++ b/components/layout_2020/dom.rs @@ -26,6 +26,7 @@ use crate::flow::BlockLevelBox; use crate::flow::inline::InlineItem; use crate::geom::PhysicalSize; use crate::replaced::{CanvasInfo, CanvasSource}; +use crate::table::TableLevelBox; use crate::taffy::TaffyItemBox; /// The data that is stored in each DOM node that is used by layout. @@ -43,6 +44,7 @@ pub(super) enum LayoutBox { BlockLevel(ArcRefCell), InlineLevel(ArcRefCell), FlexLevel(ArcRefCell), + TableLevelBox(TableLevelBox), TaffyItemBox(ArcRefCell), } @@ -62,6 +64,7 @@ impl LayoutBox { LayoutBox::TaffyItemBox(taffy_item_box) => { taffy_item_box.borrow_mut().invalidate_cached_fragment() }, + LayoutBox::TableLevelBox(table_box) => table_box.invalidate_cached_fragment(), } } } diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index 390850841bb..f02703f58d2 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -212,6 +212,7 @@ impl BoxTree { }, _ => return None, }, + LayoutBox::TableLevelBox(..) => return None, LayoutBox::TaffyItemBox(taffy_level_box) => match &taffy_level_box .borrow() .taffy_level_box diff --git a/components/layout_2020/lib.rs b/components/layout_2020/lib.rs index 640f9ff938b..9e5926e7381 100644 --- a/components/layout_2020/lib.rs +++ b/components/layout_2020/lib.rs @@ -29,6 +29,7 @@ pub mod table; pub mod traversal; use app_units::Au; +pub use cell::ArcRefCell; pub use flow::BoxTree; pub use fragment_tree::FragmentTree; use style::logical_geometry::WritingMode; diff --git a/components/layout_2020/table/construct.rs b/components/layout_2020/table/construct.rs index 6a7047aeb75..13615183788 100644 --- a/components/layout_2020/table/construct.rs +++ b/components/layout_2020/table/construct.rs @@ -6,6 +6,7 @@ use std::borrow::Cow; use std::convert::{TryFrom, TryInto}; use std::iter::repeat; +use atomic_refcell::AtomicRef; use log::warn; use script_layout_interface::wrapper_traits::ThreadSafeLayoutNode; use servo_arc::Arc; @@ -15,13 +16,13 @@ use style::selector_parser::PseudoElement; use style::str::char_is_whitespace; use super::{ - Table, TableCaption, TableSlot, TableSlotCell, TableSlotCoordinates, TableSlotOffset, - TableTrack, TableTrackGroup, TableTrackGroupType, + Table, TableCaption, TableLevelBox, TableSlot, TableSlotCell, TableSlotCoordinates, + TableSlotOffset, TableTrack, TableTrackGroup, TableTrackGroupType, }; use crate::PropagatedBoxTreeData; use crate::cell::ArcRefCell; use crate::context::LayoutContext; -use crate::dom::{BoxSlot, NodeExt}; +use crate::dom::{BoxSlot, LayoutBox, NodeExt}; use crate::dom_traversal::{Contents, NodeAndStyleInfo, NonReplacedContents, TraversalHandler}; use crate::flow::{BlockContainerBuilder, BlockFormattingContext}; use crate::formatting_contexts::{ @@ -33,9 +34,9 @@ use crate::layout_box_base::LayoutBoxBase; use crate::style_ext::{DisplayGeneratingBox, DisplayLayoutInternal}; /// A reference to a slot and its coordinates in the table -#[derive(Clone, Copy, Debug)] +#[derive(Debug)] pub(super) struct ResolvedSlotAndLocation<'a> { - pub cell: &'a TableSlotCell, + pub cell: AtomicRef<'a, TableSlotCell>, pub coords: TableSlotCoordinates, } @@ -161,7 +162,10 @@ impl Table { ) -> Vec> { let slot = self.get_slot(coords); match slot { - Some(TableSlot::Cell(cell)) => vec![ResolvedSlotAndLocation { cell, coords }], + Some(TableSlot::Cell(cell)) => vec![ResolvedSlotAndLocation { + cell: cell.borrow(), + coords, + }], Some(TableSlot::Spanned(offsets)) => offsets .iter() .flat_map(|offset| self.resolve_slot_at(coords - *offset)) @@ -241,6 +245,7 @@ impl TableBuilder { // generally less than or equal to three row groups, but if we notice a lot // of web content with more, we can consider a binary search here. for row_group in self.table.row_groups.iter() { + let row_group = row_group.borrow(); if row_group.track_range.start > n { return row_group.track_range.start - 1; } @@ -286,6 +291,7 @@ impl TableBuilder { let mut thead_index = None; let mut tfoot_index = None; for (row_group_index, row_group) in self.table.row_groups.iter().enumerate() { + let row_group = row_group.borrow(); if thead_index.is_none() && row_group.group_type == TableTrackGroupType::HeaderGroup { thead_index = Some(row_group_index); } @@ -315,25 +321,35 @@ impl TableBuilder { // Now update all track group ranges. let mut current_row_group_index = None; for (row_index, row) in self.table.rows.iter().enumerate() { + let row = row.borrow(); if current_row_group_index == row.group_index { continue; } // Finish any row group that is currently being processed. if let Some(current_group_index) = current_row_group_index { - self.table.row_groups[current_group_index].track_range.end = row_index; + self.table.row_groups[current_group_index] + .borrow_mut() + .track_range + .end = row_index; } // Start processing this new row group and update its starting index. current_row_group_index = row.group_index; if let Some(current_group_index) = current_row_group_index { - self.table.row_groups[current_group_index].track_range.start = row_index; + self.table.row_groups[current_group_index] + .borrow_mut() + .track_range + .start = row_index; } } // Finish the last row group. if let Some(current_group_index) = current_row_group_index { - self.table.row_groups[current_group_index].track_range.end = self.table.rows.len(); + self.table.row_groups[current_group_index] + .borrow_mut() + .track_range + .end = self.table.rows.len(); } } @@ -344,6 +360,7 @@ impl TableBuilder { self.table.row_groups.insert(0, removed_row_group); for row in self.table.rows.iter_mut() { + let mut row = row.borrow_mut(); match row.group_index.as_mut() { Some(group_index) if *group_index < index_to_move => *group_index += 1, Some(group_index) if *group_index == index_to_move => *group_index = 0, @@ -352,7 +369,7 @@ impl TableBuilder { } } - let row_range = self.table.row_groups[0].track_range.clone(); + let row_range = self.table.row_groups[0].borrow().track_range.clone(); if row_range.start > 0 { // Move the slots associated with the moved group. let removed_slots: Vec> = self @@ -363,7 +380,7 @@ impl TableBuilder { self.table.slots.splice(0..0, removed_slots); // Move the rows associated with the moved group. - let removed_rows: Vec = self + let removed_rows: Vec<_> = self .table .rows .splice(row_range, std::iter::empty()) @@ -385,6 +402,7 @@ impl TableBuilder { self.table.row_groups.push(removed_row_group); for row in self.table.rows.iter_mut() { + let mut row = row.borrow_mut(); match row.group_index.as_mut() { Some(group_index) if *group_index > index_to_move => *group_index -= 1, Some(group_index) if *group_index == index_to_move => { @@ -396,6 +414,7 @@ impl TableBuilder { } let row_range = self.table.row_groups[last_row_group_index] + .borrow() .track_range .clone(); if row_range.end < self.table.rows.len() { @@ -408,7 +427,7 @@ impl TableBuilder { self.table.slots.extend(removed_slots); // Move the rows associated with the moved group. - let removed_rows: Vec = self + let removed_rows: Vec<_> = self .table .rows .splice(row_range, std::iter::empty()) @@ -427,6 +446,7 @@ impl TableBuilder { let last_row_index_in_group = self.last_row_index_in_row_group_at_row_n(row_index); for cell in self.table.slots[row_index].iter_mut() { if let TableSlot::Cell(cell) = cell { + let mut cell = cell.borrow_mut(); if cell.rowspan == 1 { continue; } @@ -547,14 +567,17 @@ impl TableBuilder { /// /// Push a single cell onto the slot map, handling any colspans it may have, and /// setting up the outgoing rowspans. - pub fn add_cell(&mut self, cell: TableSlotCell) { + pub fn add_cell(&mut self, cell: ArcRefCell) { // Make sure the incoming_rowspans table is large enough // because we will be writing to it. let current_coords = self .current_coords() .expect("Should have rows before calling `add_cell`"); - let colspan = cell.colspan; - let rowspan = cell.rowspan; + + let (colspan, rowspan) = { + let cell = cell.borrow(); + (cell.colspan, cell.rowspan) + }; if self.incoming_rowspans.len() < current_coords.x + colspan { self.incoming_rowspans @@ -704,21 +727,21 @@ where row_builder.finish(); let style = anonymous_info.style.clone(); - self.push_table_row(TableTrack { + self.push_table_row(ArcRefCell::new(TableTrack { base_fragment_info: (&anonymous_info).into(), style, group_index: self.current_row_group_index, is_anonymous: true, - }); + })); } - fn push_table_row(&mut self, table_track: TableTrack) { + fn push_table_row(&mut self, table_track: ArcRefCell) { self.builder.table.rows.push(table_track); let last_row = self.builder.table.rows.len(); if let Some(index) = self.current_row_group_index { let row_group = &mut self.builder.table.row_groups[index]; - row_group.track_range.end = last_row; + row_group.borrow_mut().track_range.end = last_row; } } } @@ -749,12 +772,13 @@ where self.builder.incoming_rowspans.clear(); let next_row_index = self.builder.table.rows.len(); - self.builder.table.row_groups.push(TableTrackGroup { + let row_group = ArcRefCell::new(TableTrackGroup { base_fragment_info: info.into(), style: info.style.clone(), group_type: internal.into(), track_range: next_row_index..next_row_index, }); + self.builder.table.row_groups.push(row_group.clone()); let previous_propagated_data = self.current_propagated_data; self.current_propagated_data = self.current_propagated_data.union(&info.style); @@ -773,8 +797,9 @@ where self.current_propagated_data = previous_propagated_data; self.builder.incoming_rowspans.clear(); - // We are doing this until we have actually set a Box for this `BoxSlot`. - ::std::mem::forget(box_slot) + box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::TrackGroup( + row_group, + ))); }, DisplayLayoutInternal::TableRow => { self.finish_anonymous_row_if_needed(); @@ -790,26 +815,23 @@ where ); row_builder.finish(); - self.push_table_row(TableTrack { + let row = ArcRefCell::new(TableTrack { base_fragment_info: info.into(), style: info.style.clone(), group_index: self.current_row_group_index, is_anonymous: false, }); - - // We are doing this until we have actually set a Box for this `BoxSlot`. - ::std::mem::forget(box_slot) + self.push_table_row(row.clone()); + box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::Track(row))); }, DisplayLayoutInternal::TableColumn => { - add_column( + let column = add_column( &mut self.builder.table.columns, info, None, /* group_index */ false, /* is_anonymous */ ); - - // We are doing this until we have actually set a Box for this `BoxSlot`. - ::std::mem::forget(box_slot) + box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::Track(column))); }, DisplayLayoutInternal::TableColumnGroup => { let column_group_index = self.builder.table.column_groups.len(); @@ -839,14 +861,16 @@ where .extend(column_group_builder.columns); } - self.builder.table.column_groups.push(TableTrackGroup { + let column_group = ArcRefCell::new(TableTrackGroup { base_fragment_info: info.into(), style: info.style.clone(), group_type: internal.into(), track_range: first_column..self.builder.table.columns.len(), }); - - ::std::mem::forget(box_slot); + self.builder.table.column_groups.push(column_group.clone()); + box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::TrackGroup( + column_group, + ))); }, DisplayLayoutInternal::TableCaption => { let contents = match contents.try_into() { @@ -864,17 +888,14 @@ where }, }; - let caption = TableCaption { - context: ArcRefCell::new(IndependentFormattingContext { + let caption = ArcRefCell::new(TableCaption { + context: IndependentFormattingContext { base: LayoutBoxBase::new(info.into(), info.style.clone()), contents: IndependentFormattingContextContents::NonReplaced(contents), - }), - }; - - self.builder.table.captions.push(caption); - - // We are doing this until we have actually set a Box for this `BoxSlot`. - ::std::mem::forget(box_slot) + }, + }); + self.builder.table.captions.push(caption.clone()); + box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::Caption(caption))); }, DisplayLayoutInternal::TableCell => { self.current_anonymous_row_content @@ -968,12 +989,14 @@ where } let block_container = builder.finish(); - self.table_traversal.builder.add_cell(TableSlotCell { - base: LayoutBoxBase::new(BaseFragmentInfo::anonymous(), anonymous_info.style), - contents: BlockFormattingContext::from_block_container(block_container), - colspan: 1, - rowspan: 1, - }); + self.table_traversal + .builder + .add_cell(ArcRefCell::new(TableSlotCell { + base: LayoutBoxBase::new(BaseFragmentInfo::anonymous(), anonymous_info.style), + contents: BlockFormattingContext::from_block_container(block_container), + colspan: 1, + rowspan: 1, + })); } } @@ -1032,15 +1055,15 @@ where }; self.finish_current_anonymous_cell_if_needed(); - self.table_traversal.builder.add_cell(TableSlotCell { + + let cell = ArcRefCell::new(TableSlotCell { base: LayoutBoxBase::new(info.into(), info.style.clone()), contents, colspan, rowspan, }); - - // We are doing this until we have actually set a Box for this `BoxSlot`. - ::std::mem::forget(box_slot) + self.table_traversal.builder.add_cell(cell.clone()); + box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::Cell(cell))); }, _ => { //// TODO: Properly handle other table-like elements in the middle of a row. @@ -1068,7 +1091,7 @@ where struct TableColumnGroupBuilder { column_group_index: usize, - columns: Vec, + columns: Vec>, } impl<'dom, Node: 'dom> TraversalHandler<'dom, Node> for TableColumnGroupBuilder @@ -1083,21 +1106,22 @@ where _contents: Contents, box_slot: BoxSlot<'dom>, ) { - // We are doing this until we have actually set a Box for this `BoxSlot`. - ::std::mem::forget(box_slot); - if !matches!( display, DisplayGeneratingBox::LayoutInternal(DisplayLayoutInternal::TableColumn) ) { + // The BoxSlot destructor will check to ensure that it isn't empty but in this case, the + // DOM node doesn't produce any box, so explicitly skip the destructor here. + ::std::mem::forget(box_slot); return; } - add_column( + let column = add_column( &mut self.columns, info, Some(self.column_group_index), false, /* is_anonymous */ ); + box_slot.set(LayoutBox::TableLevelBox(TableLevelBox::Track(column))); } } @@ -1113,14 +1137,12 @@ impl From for TableTrackGroupType { } } -fn add_column<'dom, Node>( - collection: &mut Vec, +fn add_column<'dom, Node: NodeExt<'dom>>( + collection: &mut Vec>, column_info: &NodeAndStyleInfo, group_index: Option, is_anonymous: bool, -) where - Node: NodeExt<'dom>, -{ +) -> ArcRefCell { let span = if column_info.pseudo_element_type.is_none() { column_info .node @@ -1132,13 +1154,12 @@ fn add_column<'dom, Node>( 1 }; - collection.extend( - repeat(TableTrack { - base_fragment_info: column_info.into(), - style: column_info.style.clone(), - group_index, - is_anonymous, - }) - .take(span), - ); + let column = ArcRefCell::new(TableTrack { + base_fragment_info: column_info.into(), + style: column_info.style.clone(), + group_index, + is_anonymous, + }); + collection.extend(repeat(column.clone()).take(span)); + column } diff --git a/components/layout_2020/table/layout.rs b/components/layout_2020/table/layout.rs index 349ab2ff28a..bc38c5e6227 100644 --- a/components/layout_2020/table/layout.rs +++ b/components/layout_2020/table/layout.rs @@ -7,6 +7,7 @@ use std::mem; use std::ops::Range; use app_units::Au; +use atomic_refcell::AtomicRef; use log::warn; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use servo_arc::Arc; @@ -280,7 +281,8 @@ impl<'a> TableLayout<'a> { let cell = match self.table.slots[row_index][column_index] { TableSlot::Cell(ref cell) => cell, _ => continue, - }; + } + .borrow(); let layout_style = cell.layout_style(); let padding = layout_style @@ -393,12 +395,13 @@ impl<'a> TableLayout<'a> { for column_index in 0..self.table.size.width { if let Some(column) = self.table.columns.get(column_index) { + let column = column.borrow(); if is_length(&column.style.box_size(writing_mode).inline) { self.columns[column_index].constrained = true; continue; } if let Some(column_group_index) = column.group_index { - let column_group = &self.table.column_groups[column_group_index]; + let column_group = self.table.column_groups[column_group_index].borrow(); if is_length(&column_group.style.box_size(writing_mode).inline) { self.columns[column_index].constrained = true; continue; @@ -409,12 +412,13 @@ impl<'a> TableLayout<'a> { for row_index in 0..self.table.size.height { if let Some(row) = self.table.rows.get(row_index) { + let row = row.borrow(); if is_length(&row.style.box_size(writing_mode).block) { self.rows[row_index].constrained = true; continue; } if let Some(row_group_index) = row.group_index { - let row_group = &self.table.row_groups[row_group_index]; + let row_group = self.table.row_groups[row_group_index].borrow(); if is_length(&row_group.style.box_size(writing_mode).block) { self.rows[row_index].constrained = true; continue; @@ -434,7 +438,7 @@ impl<'a> TableLayout<'a> { }; let rowspan_greater_than_1 = match self.table.slots[row_index][column_index] { - TableSlot::Cell(ref cell) => cell.rowspan > 1, + TableSlot::Cell(ref cell) => cell.borrow().rowspan > 1, _ => false, }; @@ -501,7 +505,8 @@ impl<'a> TableLayout<'a> { let cell = match self.table.get_slot(coords) { Some(TableSlot::Cell(cell)) => cell, _ => continue, - }; + } + .borrow(); if cell.colspan != 1 { colspan_cell_constraints.push(ColspanToDistribute { @@ -708,8 +713,9 @@ impl<'a> TableLayout<'a> { .captions .iter() .map(|caption| { - let context = caption.context.borrow(); - context + caption + .borrow() + .context .outer_inline_content_sizes( layout_context, &containing_block, @@ -1075,9 +1081,11 @@ impl<'a> TableLayout<'a> { let collect_for_nearest_positioned_ancestor = parent_positioning_context .collects_for_nearest_positioned_ancestor() || self.table.rows.get(row_index).is_some_and(|row| { + let row = row.borrow(); let row_group_collects_for_nearest_positioned_ancestor = row.group_index.is_some_and(|group_index| { self.table.row_groups[group_index] + .borrow() .style .establishes_containing_block_for_absolute_descendants( FragmentFlags::empty(), @@ -1098,6 +1106,7 @@ impl<'a> TableLayout<'a> { return None; }; + let cell = cell.borrow(); let area = LogicalSides { inline_start: column_index, inline_end: column_index + cell.colspan, @@ -1192,6 +1201,7 @@ impl<'a> TableLayout<'a> { }, }; + let cell = cell.borrow(); let outer_block_size = layout.outer_block_size(); if cell.rowspan == 1 { max_row_height.max_assign(outer_block_size); @@ -1251,7 +1261,7 @@ impl<'a> TableLayout<'a> { let cell_measure = &self.cell_measures[row_index][column_index].block; let cell = match self.table.slots[row_index][column_index] { - TableSlot::Cell(ref cell) if cell.rowspan > 1 => cell, + TableSlot::Cell(ref cell) if cell.borrow().rowspan > 1 => cell, TableSlot::Cell(_) => { // If this is an originating cell, that isn't spanning, then we make sure the row is // at least big enough to hold the cell. @@ -1263,7 +1273,7 @@ impl<'a> TableLayout<'a> { cells_to_distribute.push(RowspanToDistribute { coordinates: TableSlotCoordinates::new(column_index, row_index), - cell, + cell: cell.borrow(), measure: cell_measure, }); } @@ -1491,8 +1501,7 @@ impl<'a> TableLayout<'a> { layout_context: &LayoutContext, parent_positioning_context: &mut PositioningContext, ) -> BoxFragment { - let context = caption.context.borrow(); - let mut positioning_context = PositioningContext::new_for_style(context.style()); + let mut positioning_context = PositioningContext::new_for_style(caption.context.style()); let containing_block = &ContainingBlock { size: ContainingBlockSize { inline: self.table_width + self.pbm.padding_border_sums.inline, @@ -1506,7 +1515,7 @@ impl<'a> TableLayout<'a> { // stretch block size. https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing let ignore_block_margins_for_stretch = LogicalSides1D::new(false, false); - let mut box_fragment = context.layout_in_flow_block_level( + let mut box_fragment = caption.context.layout_in_flow_block_level( layout_context, positioning_context .as_mut() @@ -1596,13 +1605,14 @@ impl<'a> TableLayout<'a> { table_layout .fragments .extend(self.table.captions.iter().filter_map(|caption| { - if caption.context.borrow().style().clone_caption_side() != CaptionSide::Top { + let caption = caption.borrow(); + if caption.context.style().clone_caption_side() != CaptionSide::Top { return None; } let original_positioning_context_length = positioning_context.len(); let mut caption_fragment = - self.layout_caption(caption, layout_context, positioning_context); + self.layout_caption(&caption, layout_context, positioning_context); // The caption is not placed yet. Construct a rectangle for it in the adjusted containing block // for the table children and only then convert the result to physical geometry. @@ -1698,13 +1708,14 @@ impl<'a> TableLayout<'a> { table_layout .fragments .extend(self.table.captions.iter().filter_map(|caption| { - if caption.context.borrow().style().clone_caption_side() != CaptionSide::Bottom { + let caption = caption.borrow(); + if caption.context.style().clone_caption_side() != CaptionSide::Bottom { return None; } let original_positioning_context_length = positioning_context.len(); let mut caption_fragment = - self.layout_caption(caption, layout_context, positioning_context); + self.layout_caption(&caption, layout_context, positioning_context); // The caption is not placed yet. Construct a rectangle for it in the adjusted containing block // for the table children and only then convert the result to physical geometry. @@ -1820,9 +1831,9 @@ impl<'a> TableLayout<'a> { continue; } - let table_row = &self.table.rows[row_index]; + let table_row = self.table.rows[row_index].borrow(); let mut row_fragment_layout = RowFragmentLayout::new( - table_row, + &table_row, row_index, &table_and_track_dimensions, &self.table.style, @@ -1845,7 +1856,7 @@ impl<'a> TableLayout<'a> { // Then, create a new RowGroupFragmentLayout for the current and potentially subsequent rows. if let Some(new_group_index) = table_row.group_index { row_group_fragment_layout = Some(RowGroupFragmentLayout::new( - &self.table.row_groups[new_group_index], + &self.table.row_groups[new_group_index].borrow(), new_group_index, &table_and_track_dimensions, )); @@ -1960,25 +1971,28 @@ impl<'a> TableLayout<'a> { let Some(row) = &self.table.rows.get(row_index) else { return false; }; + + let row = row.borrow(); if row.style.get_inherited_box().visibility == Visibility::Collapse { return true; } let row_group = match row.group_index { - Some(group_index) => &self.table.row_groups[group_index], + Some(group_index) => self.table.row_groups[group_index].borrow(), None => return false, }; row_group.style.get_inherited_box().visibility == Visibility::Collapse } fn is_column_collapsed(&self, column_index: usize) -> bool { - let Some(col) = &self.table.columns.get(column_index) else { + let Some(column) = &self.table.columns.get(column_index) else { return false; }; - if col.style.get_inherited_box().visibility == Visibility::Collapse { + let column = column.borrow(); + if column.style.get_inherited_box().visibility == Visibility::Collapse { return true; } - let col_group = match col.group_index { - Some(group_index) => &self.table.column_groups[group_index], + let col_group = match column.group_index { + Some(group_index) => self.table.column_groups[group_index].borrow(), None => return false, }; col_group.style.get_inherited_box().visibility == Visibility::Collapse @@ -2017,7 +2031,8 @@ impl<'a> TableLayout<'a> { warn!("Did not find a non-spanned cell at index with layout."); return; }, - }; + } + .borrow(); // If this cell has baseline alignment, it can adjust the table's overall baseline. let row_block_offset = row_fragment_layout.rect.start_corner.block; @@ -2067,16 +2082,18 @@ impl<'a> TableLayout<'a> { let column = self.table.columns.get(column_index); let column_group = column - .and_then(|column| column.group_index) + .and_then(|column| column.borrow().group_index) .and_then(|index| self.table.column_groups.get(index)); if let Some(column_group) = column_group { - let rect = make_relative_to_row_start(dimensions.get_column_group_rect(column_group)); + let column_group = column_group.borrow(); + let rect = make_relative_to_row_start(dimensions.get_column_group_rect(&column_group)); fragment.add_extra_background(ExtraBackground { style: column_group.style.clone(), rect, }) } if let Some(column) = column { + let column = column.borrow(); if !column.is_anonymous { let rect = make_relative_to_row_start(dimensions.get_column_rect(column_index)); fragment.add_extra_background(ExtraBackground { @@ -2087,16 +2104,18 @@ impl<'a> TableLayout<'a> { } let row = self.table.rows.get(row_index); let row_group = row - .and_then(|row| row.group_index) + .and_then(|row| row.borrow().group_index) .and_then(|index| self.table.row_groups.get(index)); if let Some(row_group) = row_group { - let rect = make_relative_to_row_start(dimensions.get_row_group_rect(row_group)); + let rect = + make_relative_to_row_start(dimensions.get_row_group_rect(&row_group.borrow())); fragment.add_extra_background(ExtraBackground { - style: row_group.style.clone(), + style: row_group.borrow().style.clone(), rect, }) } if let Some(row) = row { + let row = row.borrow(); let rect = make_relative_to_row_start(row_fragment_layout.rect); fragment.add_extra_background(ExtraBackground { style: row.style.clone(), @@ -2114,11 +2133,12 @@ impl<'a> TableLayout<'a> { fragments: &mut Vec, ) { for column_group in self.table.column_groups.iter() { + let column_group = column_group.borrow(); if !column_group.is_empty() { fragments.push(Fragment::Positioning(PositioningFragment::new_empty( column_group.base_fragment_info, dimensions - .get_column_group_rect(column_group) + .get_column_group_rect(&column_group) .as_physical(None), column_group.style.clone(), ))); @@ -2126,6 +2146,7 @@ impl<'a> TableLayout<'a> { } for (column_index, column) in self.table.columns.iter().enumerate() { + let column = column.borrow(); fragments.push(Fragment::Positioning(PositioningFragment::new_empty( column.base_fragment_info, dimensions.get_column_rect(column_index).as_physical(None), @@ -2190,7 +2211,8 @@ impl<'a> TableLayout<'a> { let cell = match self.table.slots[row_index][column_index] { TableSlot::Cell(ref cell) => cell, _ => continue, - }; + } + .borrow(); let block_range = row_index..row_index + cell.rowspan; let inline_range = column_index..column_index + cell.colspan; hide_inner_borders(&mut collapsed_borders, &block_range, &inline_range); @@ -2203,6 +2225,7 @@ impl<'a> TableLayout<'a> { } } for (row_index, row) in self.table.rows.iter().enumerate() { + let row = row.borrow(); apply_border( &mut collapsed_borders, &row.layout_style(), @@ -2211,6 +2234,7 @@ impl<'a> TableLayout<'a> { ); } for row_group in &self.table.row_groups { + let row_group = row_group.borrow(); apply_border( &mut collapsed_borders, &row_group.layout_style(), @@ -2219,6 +2243,7 @@ impl<'a> TableLayout<'a> { ); } for (column_index, column) in self.table.columns.iter().enumerate() { + let column = column.borrow(); apply_border( &mut collapsed_borders, &column.layout_style(), @@ -2227,6 +2252,7 @@ impl<'a> TableLayout<'a> { ); } for column_group in &self.table.column_groups { + let column_group = column_group.borrow(); apply_border( &mut collapsed_borders, &column_group.layout_style(), @@ -2599,7 +2625,8 @@ impl Table { let column = match self.columns.get(column_index) { Some(column) => column, None => return CellOrTrackMeasure::zero(), - }; + } + .borrow(); let CellOrColumnOuterSizes { preferred: preferred_size, @@ -2644,6 +2671,7 @@ impl Table { // In the block axis, the min-content and max-content sizes are the same // (except for new layout boxes like grid and flex containers). Note that // other browsers don't seem to use the min and max sizing properties here. + let row = row.borrow(); let size = row.style.box_size(writing_mode); let max_size = row.style.max_box_size(writing_mode); let percentage_contribution = get_size_percentage_contribution(&size, &max_size); @@ -2979,7 +3007,7 @@ impl CellOrColumnOuterSizes { struct RowspanToDistribute<'a> { coordinates: TableSlotCoordinates, - cell: &'a TableSlotCell, + cell: AtomicRef<'a, TableSlotCell>, measure: &'a CellOrTrackMeasure, } diff --git a/components/layout_2020/table/mod.rs b/components/layout_2020/table/mod.rs index 81bc9285b5a..749c2fbac04 100644 --- a/components/layout_2020/table/mod.rs +++ b/components/layout_2020/table/mod.rs @@ -71,6 +71,7 @@ mod layout; use std::ops::Range; use app_units::Au; +use atomic_refcell::AtomicRef; pub(crate) use construct::AnonymousTableContent; pub use construct::TableBuilder; use euclid::{Point2D, Size2D, UnknownUnit, Vector2D}; @@ -107,20 +108,20 @@ pub struct Table { grid_base_fragment_info: BaseFragmentInfo, /// The captions for this table. - pub captions: Vec, + pub captions: Vec>, /// The column groups for this table. - pub column_groups: Vec, + pub column_groups: Vec>, /// The columns of this table defined by ` | display: table-column-group` /// and ` | display: table-column` elements as well as `display: table-column`. - pub columns: Vec, + pub columns: Vec>, /// The rows groups for this table defined by ``, ``, and ``. - pub row_groups: Vec, + pub row_groups: Vec>, /// The rows of this table defined by `` or `display: table-row` elements. - pub rows: Vec, + pub rows: Vec>, /// The content of the slots of this table. pub slots: Vec>, @@ -175,11 +176,14 @@ impl Table { } } - fn resolve_first_cell(&self, coords: TableSlotCoordinates) -> Option<&TableSlotCell> { + fn resolve_first_cell( + &self, + coords: TableSlotCoordinates, + ) -> Option> { let resolved_coords = self.resolve_first_cell_coords(coords)?; let slot = self.get_slot(resolved_coords); match slot { - Some(TableSlot::Cell(cell)) => Some(cell), + Some(TableSlot::Cell(cell)) => Some(cell.borrow()), _ => unreachable!( "Spanned slot should not point to an empty cell or another spanned slot." ), @@ -234,7 +238,7 @@ impl TableSlotCell { /// In case of table model errors, it may be multiple references pub enum TableSlot { /// A table cell, with a colspan and a rowspan. - Cell(TableSlotCell), + Cell(ArcRefCell), /// This slot is spanned by one or more multiple cells earlier in the table, which are /// found at the given negative coordinate offsets. The vector is in the order of most @@ -317,7 +321,7 @@ impl TableTrackGroup { #[derive(Debug)] pub struct TableCaption { /// The contents of this cell, with its own layout. - context: ArcRefCell, + context: IndependentFormattingContext, } /// A calculated collapsed border. @@ -340,3 +344,30 @@ pub(crate) struct TableLayoutStyle<'a> { table: &'a Table, layout: Option<&'a TableLayout<'a>>, } + +/// Table parts that are stored in the DOM. This is used in order to map from +/// the DOM to the box tree and will eventually be important for incremental +/// layout. +pub(crate) enum TableLevelBox { + Caption(ArcRefCell), + Cell(ArcRefCell), + #[allow(dead_code)] + TrackGroup(ArcRefCell), + #[allow(dead_code)] + Track(ArcRefCell), +} + +impl TableLevelBox { + pub(crate) fn invalidate_cached_fragment(&self) { + match self { + TableLevelBox::Caption(caption) => { + caption.borrow().context.base.invalidate_cached_fragment(); + }, + TableLevelBox::Cell(cell) => { + cell.borrow().base.invalidate_cached_fragment(); + }, + TableLevelBox::TrackGroup(..) => {}, + TableLevelBox::Track(..) => {}, + } + } +} diff --git a/components/layout_2020/tests/tables.rs b/components/layout_2020/tests/tables.rs index 5b1129bf999..559a409d19b 100644 --- a/components/layout_2020/tests/tables.rs +++ b/components/layout_2020/tests/tables.rs @@ -6,6 +6,7 @@ mod tables { use euclid::Vector2D; + use layout_2020::ArcRefCell; use layout_2020::table::{Table, TableBuilder, TableSlot, TableSlotCell, TableSlotOffset}; fn row_lengths(table: &Table) -> Vec { @@ -14,7 +15,7 @@ mod tables { fn slot_is_cell_with_id(slot: &TableSlot, id: usize) -> bool { match slot { - TableSlot::Cell(cell) if cell.node_id() == id => true, + TableSlot::Cell(cell) if cell.borrow().node_id() == id => true, _ => false, } } @@ -51,13 +52,13 @@ mod tables { let mut table_builder = TableBuilder::new_for_tests(); table_builder.start_row(); - table_builder.add_cell(TableSlotCell::mock_for_testing(1, 1, 1)); - table_builder.add_cell(TableSlotCell::mock_for_testing(2, 1, 1)); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(1, 1, 1))); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(2, 1, 1))); table_builder.end_row(); table_builder.start_row(); - table_builder.add_cell(TableSlotCell::mock_for_testing(3, 1, 1)); - table_builder.add_cell(TableSlotCell::mock_for_testing(4, 1, 1)); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(3, 1, 1))); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(4, 1, 1))); table_builder.end_row(); let table = table_builder.finish(); @@ -74,13 +75,13 @@ mod tables { let mut table_builder = TableBuilder::new_for_tests(); table_builder.start_row(); - table_builder.add_cell(TableSlotCell::mock_for_testing(1, 1, 1)); - table_builder.add_cell(TableSlotCell::mock_for_testing(2, 1, 1)); - table_builder.add_cell(TableSlotCell::mock_for_testing(3, 1, 2)); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(1, 1, 1))); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(2, 1, 1))); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(3, 1, 2))); table_builder.end_row(); table_builder.start_row(); - table_builder.add_cell(TableSlotCell::mock_for_testing(4, 1, 1)); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(4, 1, 1))); table_builder.end_row(); let table = table_builder.finish(); @@ -103,21 +104,21 @@ mod tables { let mut table_builder = TableBuilder::new_for_tests(); table_builder.start_row(); - table_builder.add_cell(TableSlotCell::mock_for_testing(1, 3, 1)); - table_builder.add_cell(TableSlotCell::mock_for_testing(2, 1, 1)); - table_builder.add_cell(TableSlotCell::mock_for_testing(3, 1, 1)); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(1, 3, 1))); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(2, 1, 1))); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(3, 1, 1))); table_builder.end_row(); table_builder.start_row(); - table_builder.add_cell(TableSlotCell::mock_for_testing(4, 1, 1)); - table_builder.add_cell(TableSlotCell::mock_for_testing(5, 3, 1)); - table_builder.add_cell(TableSlotCell::mock_for_testing(6, 1, 1)); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(4, 1, 1))); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(5, 3, 1))); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(6, 1, 1))); table_builder.end_row(); table_builder.start_row(); - table_builder.add_cell(TableSlotCell::mock_for_testing(7, 1, 1)); - table_builder.add_cell(TableSlotCell::mock_for_testing(8, 1, 1)); - table_builder.add_cell(TableSlotCell::mock_for_testing(9, 3, 1)); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(7, 1, 1))); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(8, 1, 1))); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(9, 3, 1))); table_builder.end_row(); let table = table_builder.finish(); @@ -165,13 +166,13 @@ mod tables { let mut table_builder = TableBuilder::new_for_tests(); table_builder.start_row(); - table_builder.add_cell(TableSlotCell::mock_for_testing(1, 1, 1)); - table_builder.add_cell(TableSlotCell::mock_for_testing(2, 1, 1)); - table_builder.add_cell(TableSlotCell::mock_for_testing(3, 1, 2)); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(1, 1, 1))); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(2, 1, 1))); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(3, 1, 2))); table_builder.end_row(); table_builder.start_row(); - table_builder.add_cell(TableSlotCell::mock_for_testing(4, 3, 1)); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(4, 3, 1))); table_builder.end_row(); let table = table_builder.finish(); @@ -197,9 +198,9 @@ mod tables { let mut table_builder = TableBuilder::new_for_tests(); table_builder.start_row(); - table_builder.add_cell(TableSlotCell::mock_for_testing(1, 1, 1)); - table_builder.add_cell(TableSlotCell::mock_for_testing(2, 1, 1)); - table_builder.add_cell(TableSlotCell::mock_for_testing(3, 1, 0)); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(1, 1, 1))); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(2, 1, 1))); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(3, 1, 0))); table_builder.end_row(); table_builder.start_row(); @@ -235,12 +236,12 @@ mod tables { let mut table_builder = TableBuilder::new_for_tests(); table_builder.start_row(); - table_builder.add_cell(TableSlotCell::mock_for_testing(1, 1, 1)); - table_builder.add_cell(TableSlotCell::mock_for_testing(2, 1, 30)); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(1, 1, 1))); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(2, 1, 30))); table_builder.end_row(); table_builder.start_row(); - table_builder.add_cell(TableSlotCell::mock_for_testing(3, 2, 1)); + table_builder.add_cell(ArcRefCell::new(TableSlotCell::mock_for_testing(3, 2, 1))); table_builder.end_row(); assert_eq!(table_builder.incoming_rowspans, vec![0, 28]);