aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout_2020/table/construct.rs
diff options
context:
space:
mode:
authorMartin Robinson <mrobinson@igalia.com>2024-01-19 14:20:20 +0100
committerGitHub <noreply@github.com>2024-01-19 13:20:20 +0000
commitfc31e69f79a68408fdd376a52942587a8fca9170 (patch)
tree5c294519595326791e0464b84eb987f5f1597e14 /components/layout_2020/table/construct.rs
parent3d520f266800e0035c429ddf2a3b45922f502ebd (diff)
downloadservo-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.rs60
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`.