diff options
author | Martin Robinson <mrobinson@igalia.com> | 2024-01-19 14:20:20 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-19 13:20:20 +0000 |
commit | fc31e69f79a68408fdd376a52942587a8fca9170 (patch) | |
tree | 5c294519595326791e0464b84eb987f5f1597e14 /components/layout_2020/table/construct.rs | |
parent | 3d520f266800e0035c429ddf2a3b45922f502ebd (diff) | |
download | servo-fc31e69f79a68408fdd376a52942587a8fca9170.tar.gz servo-fc31e69f79a68408fdd376a52942587a8fca9170.zip |
layout: Add *very* basic support for table layout (#31121)
* layout: Add *very* basic support for table layout
This is the first step to proper table layout. It implements a naive
layout algorithm, notably only taking into account the preferred widths
of the first table row. Still, it causes some float tests to start
passing, so turn on the `layout.tables.enabled` preference for those
directories.
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
* Address review comments
* Fix a crash with rowspan=0
* Turn on pref and update results for `/css/css-tables` and `/css/CSS2/tables`
---------
Co-authored-by: Oriol Brufau <obrufau@igalia.com>
Diffstat (limited to 'components/layout_2020/table/construct.rs')
-rw-r--r-- | components/layout_2020/table/construct.rs | 60 |
1 files changed, 46 insertions, 14 deletions
diff --git a/components/layout_2020/table/construct.rs b/components/layout_2020/table/construct.rs index 92920a728f9..8b42a709962 100644 --- a/components/layout_2020/table/construct.rs +++ b/components/layout_2020/table/construct.rs @@ -7,6 +7,8 @@ use std::convert::{TryFrom, TryInto}; use log::warn; use script_layout_interface::wrapper_traits::ThreadSafeLayoutNode; +use servo_arc::Arc; +use style::properties::ComputedValues; use style::selector_parser::PseudoElement; use style::str::char_is_whitespace; use style::values::specified::TextDecorationLine; @@ -20,13 +22,14 @@ use crate::formatting_contexts::{ IndependentFormattingContext, NonReplacedFormattingContext, NonReplacedFormattingContextContents, }; +use crate::fragment_tree::{BaseFragmentInfo, FragmentFlags, Tag}; use crate::style_ext::{DisplayGeneratingBox, DisplayLayoutInternal}; /// A reference to a slot and its coordinates in the table #[derive(Clone, Copy, Debug)] -struct ResolvedSlotAndLocation<'a> { - cell: &'a TableSlotCell, - coords: TableSlotCoordinates, +pub(super) struct ResolvedSlotAndLocation<'a> { + pub cell: &'a TableSlotCell, + pub coords: TableSlotCoordinates, } impl<'a> ResolvedSlotAndLocation<'a> { @@ -114,12 +117,15 @@ impl Table { /// Push a new slot into the last row of this table. fn push_new_slot_to_last_row(&mut self, slot: TableSlot) { - self.slots.last_mut().expect("Should have rows").push(slot) - } + let last_row = match self.slots.last_mut() { + Some(row) => row, + None => { + unreachable!("Should have some rows before calling `push_new_slot_to_last_row`") + }, + }; - /// Convenience method for get() that returns a SlotAndLocation - fn get_slot<'a>(&'a self, coords: TableSlotCoordinates) -> Option<&'a TableSlot> { - self.slots.get(coords.y)?.get(coords.x) + self.size.width = self.size.width.max(last_row.len() + 1); + last_row.push(slot); } /// Find [`ResolvedSlotAndLocation`] of all the slots that cover the slot at the given @@ -127,7 +133,7 @@ impl Table { /// the target and returns a [`ResolvedSlotAndLocation`] for each of them. If there is /// no slot at the given coordinates or that slot is an empty space, an empty vector /// is returned. - fn resolve_slot_at<'a>( + pub(super) fn resolve_slot_at<'a>( &'a self, coords: TableSlotCoordinates, ) -> Vec<ResolvedSlotAndLocation<'a>> { @@ -191,7 +197,6 @@ impl TableSlot { } } -#[derive(Default)] pub struct TableBuilder { /// The table that we are building. table: Table, @@ -209,7 +214,22 @@ pub struct TableBuilder { } impl TableBuilder { - pub fn finish(self) -> Table { + pub(super) fn new(style: Arc<ComputedValues>) -> Self { + Self { + table: Table::new(style), + incoming_rowspans: Vec::new(), + } + } + + pub fn new_for_tests() -> Self { + Self::new(ComputedValues::initial_values().to_arc()) + } + + pub fn finish(mut self) -> Table { + // Make sure that every row has the same number of cells. + for row in self.table.slots.iter_mut() { + row.resize_with(self.table.size.width, || TableSlot::Empty); + } self.table } @@ -227,6 +247,7 @@ impl TableBuilder { pub fn start_row<'builder>(&'builder mut self) { self.table.slots.push(Vec::new()); + self.table.size.height += 1; self.create_slots_for_cells_above_with_rowspan(true); } @@ -385,7 +406,7 @@ where context, info, propagated_text_decoration_line, - builder: Default::default(), + builder: TableBuilder::new(info.style.clone()), current_anonymous_row_content: Vec::new(), } } @@ -592,12 +613,22 @@ where } } + let tag = Tag::new_pseudo( + self.info.node.opaque(), + Some(PseudoElement::ServoAnonymousTableCell), + ); + let base_fragment_info = BaseFragmentInfo { + tag, + flags: FragmentFlags::empty(), + }; + let block_container = builder.finish(); self.table_traversal.builder.add_cell(TableSlotCell { contents: BlockFormattingContext::from_block_container(block_container), colspan: 1, rowspan: 1, - id: 0, // This is just an id used for testing purposes. + style: anonymous_info.style, + base_fragment_info, }); } } @@ -657,7 +688,8 @@ where contents, colspan, rowspan, - id: 0, // This is just an id used for testing purposes. + style: info.style.clone(), + base_fragment_info: info.into(), }); // We are doing this until we have actually set a Box for this `BoxSlot`. |