layout: Properly parent table-row and table-row-group (#31619)

Put table cell content fragments into a hieararchy of fragments that
include their table row and table row group fragments. This ensures that
things like relative positioning and transforms set on rows and row
groups properly affect cells and cell content.

Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Martin Robinson 2024-03-14 11:33:42 +01:00 committed by GitHub
parent 0e78c8114b
commit 78fe461ff2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 439 additions and 160 deletions

View file

@ -30,7 +30,9 @@ use wr::{BoxShadowClipMode, ScrollSensitivity};
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::display_list::conversions::ToWebRender; use crate::display_list::conversions::ToWebRender;
use crate::display_list::stacking_context::StackingContextSection; use crate::display_list::stacking_context::StackingContextSection;
use crate::fragment_tree::{BoxFragment, Fragment, FragmentTree, Tag, TextFragment}; use crate::fragment_tree::{
BackgroundMode, BoxFragment, Fragment, FragmentTree, Tag, TextFragment,
};
use crate::geom::{LogicalRect, PhysicalPoint, PhysicalRect}; use crate::geom::{LogicalRect, PhysicalPoint, PhysicalRect};
use crate::replaced::IntrinsicSizes; use crate::replaced::IntrinsicSizes;
use crate::style_ext::ComputedValuesExt; use crate::style_ext::ComputedValuesExt;
@ -611,19 +613,29 @@ impl<'a> BuilderForBoxFragment<'a> {
return; return;
} }
for extra_background in self.fragment.extra_backgrounds.iter() { // If this BoxFragment does not paint a background, do nothing.
let positioning_area: LogicalRect<Length> = extra_background.rect.clone().into(); if let BackgroundMode::None = self.fragment.background_mode {
let painter = BackgroundPainter { return;
style: &extra_background.style, }
painting_area_override: None,
positioning_area_override: Some( // Paint all extra backgrounds for this BoxFragment. These are painted first, as that's
positioning_area // the order that they are expected to be painted for table cells (where this feature
.to_physical(self.fragment.style.writing_mode, self.containing_block) // is used).
.translate(self.containing_block.origin.to_vector()) if let BackgroundMode::Extra(ref extra_backgrounds) = self.fragment.background_mode {
.to_webrender(), for extra_background in extra_backgrounds {
), let positioning_area: LogicalRect<Length> = extra_background.rect.clone().into();
}; let painter = BackgroundPainter {
self.build_background_for_painter(builder, &painter); style: &extra_background.style,
painting_area_override: None,
positioning_area_override: Some(
positioning_area
.to_physical(self.fragment.style.writing_mode, self.containing_block)
.translate(self.containing_block.origin.to_vector())
.to_webrender(),
),
};
self.build_background_for_painter(builder, &painter);
}
} }
let painter = BackgroundPainter { let painter = BackgroundPainter {

View file

@ -21,6 +21,19 @@ use crate::geom::{
}; };
use crate::style_ext::ComputedValuesExt; use crate::style_ext::ComputedValuesExt;
/// Describes how a [`BoxFragment`] paints its background.
pub(crate) enum BackgroundMode {
/// Draw the normal [`BoxFragment`] background as well as the extra backgrounds
/// based on the style and positioning rectangles in this data structure.
Extra(Vec<ExtraBackground>),
/// Do not draw a background for this Fragment. This is used for elements like
/// table tracks and table track groups, which rely on cells to paint their
/// backgrounds.
None,
/// Draw the background normally, getting information from the Fragment style.
Normal,
}
pub(crate) struct ExtraBackground { pub(crate) struct ExtraBackground {
pub style: ServoArc<ComputedValues>, pub style: ServoArc<ComputedValues>,
pub rect: LogicalRect<Au>, pub rect: LogicalRect<Au>,
@ -70,7 +83,7 @@ pub(crate) struct BoxFragment {
pub(crate) resolved_sticky_insets: Option<PhysicalSides<LengthOrAuto>>, pub(crate) resolved_sticky_insets: Option<PhysicalSides<LengthOrAuto>>,
#[serde(skip_serializing)] #[serde(skip_serializing)]
pub extra_backgrounds: Vec<ExtraBackground>, pub background_mode: BackgroundMode,
} }
impl BoxFragment { impl BoxFragment {
@ -160,7 +173,7 @@ impl BoxFragment {
scrollable_overflow_from_children, scrollable_overflow_from_children,
overconstrained, overconstrained,
resolved_sticky_insets: None, resolved_sticky_insets: None,
extra_backgrounds: Vec::new(), background_mode: BackgroundMode::Normal,
} }
} }
@ -178,7 +191,14 @@ impl BoxFragment {
} }
pub fn add_extra_background(&mut self, extra_background: ExtraBackground) { pub fn add_extra_background(&mut self, extra_background: ExtraBackground) {
self.extra_backgrounds.push(extra_background); match self.background_mode {
BackgroundMode::Extra(ref mut backgrounds) => backgrounds.push(extra_background),
_ => self.background_mode = BackgroundMode::Extra(vec![extra_background]),
}
}
pub fn set_does_not_paint_background(&mut self) {
self.background_mode = BackgroundMode::None;
} }
pub fn scrollable_overflow( pub fn scrollable_overflow(

View file

@ -4,7 +4,7 @@
use std::convert::From; use std::convert::From;
use std::fmt; use std::fmt;
use std::ops::{Add, AddAssign, Sub}; use std::ops::{Add, AddAssign, Sub, SubAssign};
use app_units::Au; use app_units::Au;
use serde::Serialize; use serde::Serialize;
@ -26,7 +26,7 @@ pub type LengthOrAuto = AutoOr<Length>;
pub type AuOrAuto = AutoOr<Au>; pub type AuOrAuto = AutoOr<Au>;
pub type LengthPercentageOrAuto<'a> = AutoOr<&'a LengthPercentage>; pub type LengthPercentageOrAuto<'a> = AutoOr<&'a LengthPercentage>;
#[derive(Clone, Serialize)] #[derive(Clone, Copy, Serialize)]
pub struct LogicalVec2<T> { pub struct LogicalVec2<T> {
pub inline: T, pub inline: T,
pub block: T, pub block: T,
@ -117,6 +117,34 @@ where
} }
} }
impl<T> AddAssign<LogicalVec2<T>> for LogicalVec2<T>
where
T: AddAssign<T> + Copy,
{
fn add_assign(&mut self, other: LogicalVec2<T>) {
self.add_assign(&other);
}
}
impl<T> SubAssign<&'_ LogicalVec2<T>> for LogicalVec2<T>
where
T: SubAssign<T> + Copy,
{
fn sub_assign(&mut self, other: &'_ LogicalVec2<T>) {
self.inline -= other.inline;
self.block -= other.block;
}
}
impl<T> SubAssign<LogicalVec2<T>> for LogicalVec2<T>
where
T: SubAssign<T> + Copy,
{
fn sub_assign(&mut self, other: LogicalVec2<T>) {
self.sub_assign(&other);
}
}
impl<T: Zero> LogicalVec2<T> { impl<T: Zero> LogicalVec2<T> {
pub fn zero() -> Self { pub fn zero() -> Self {
Self { Self {

View file

@ -639,10 +639,10 @@ where
.stylist .stylist
.style_for_anonymous::<Node::ConcreteElement>( .style_for_anonymous::<Node::ConcreteElement>(
&context.shared_context().guards, &context.shared_context().guards,
&PseudoElement::ServoAnonymousTableCell, &PseudoElement::ServoAnonymousTableRow,
&self.info.style, &self.info.style,
); );
let anonymous_info = self.info.new_anonymous(anonymous_style); let anonymous_info = self.info.new_anonymous(anonymous_style.clone());
let mut row_builder = let mut row_builder =
TableRowBuilder::new(self, &anonymous_info, self.current_text_decoration_line); TableRowBuilder::new(self, &anonymous_info, self.current_text_decoration_line);
@ -663,6 +663,23 @@ where
} }
row_builder.finish(); row_builder.finish();
self.push_table_row(TableTrack {
base_fragment_info: (&anonymous_info).into(),
style: anonymous_style,
group_index: self.current_row_group_index,
is_anonymous: true,
});
}
fn push_table_row(&mut self, table_track: TableTrack) {
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;
}
} }
} }
@ -714,6 +731,7 @@ where
info, info,
self, self,
); );
self.finish_anonymous_row_if_needed();
self.current_row_group_index = None; self.current_row_group_index = None;
self.current_text_decoration_line = previous_text_decoration_line; self.current_text_decoration_line = previous_text_decoration_line;
@ -736,21 +754,13 @@ where
); );
row_builder.finish(); row_builder.finish();
self.builder.table.rows.push(TableTrack { self.push_table_row(TableTrack {
base_fragment_info: info.into(), base_fragment_info: info.into(),
style: info.style.clone(), style: info.style.clone(),
group_index: self.current_row_group_index, group_index: self.current_row_group_index,
is_anonymous: false, is_anonymous: false,
}); });
let last_row = self.builder.table.rows.len();
let row_group = self
.current_row_group_index
.map(|index| &mut self.builder.table.row_groups[index]);
if let Some(row_group) = row_group {
row_group.track_range.end = last_row;
}
// We are doing this until we have actually set a Box for this `BoxSlot`. // We are doing this until we have actually set a Box for this `BoxSlot`.
::std::mem::forget(box_slot) ::std::mem::forget(box_slot)
}, },

View file

@ -18,14 +18,15 @@ 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, TableSlot, TableSlotCell, TableTrackGroup}; use super::{Table, 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::{
BoxFragment, CollapsedBlockMargins, ExtraBackground, Fragment, PositioningFragment, BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, ExtraBackground, Fragment,
PositioningFragment,
}; };
use crate::geom::{AuOrAuto, LengthPercentageOrAuto, LogicalRect, LogicalSides, LogicalVec2}; use crate::geom::{AuOrAuto, LengthPercentageOrAuto, LogicalRect, LogicalSides, LogicalVec2};
use crate::positioned::{PositioningContext, PositioningContextLength}; use crate::positioned::{relative_adjustement, PositioningContext, PositioningContextLength};
use crate::sizing::ContentSizes; use crate::sizing::ContentSizes;
use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin}; use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin};
use crate::table::TableSlotCoordinates; use crate::table::TableSlotCoordinates;
@ -84,6 +85,7 @@ pub(crate) struct TableLayout<'a> {
column_measures: Vec<CellOrTrackMeasure>, column_measures: Vec<CellOrTrackMeasure>,
distributed_column_widths: Vec<Au>, distributed_column_widths: Vec<Au>,
row_sizes: Vec<Au>, row_sizes: Vec<Au>,
/// The accumulated baseline of each row, relative to the top of the row.
row_baselines: Vec<Au>, row_baselines: Vec<Au>,
cells_laid_out: Vec<Vec<Option<CellLayout>>>, cells_laid_out: Vec<Vec<Option<CellLayout>>>,
basis_for_cell_padding_percentage: Au, basis_for_cell_padding_percentage: Au,
@ -968,9 +970,25 @@ impl<'a> TableLayout<'a> {
parent_positioning_context: &mut PositioningContext, parent_positioning_context: &mut PositioningContext,
) { ) {
for row_index in 0..self.table.slots.len() { for row_index in 0..self.table.slots.len() {
let row = &self.table.slots[row_index]; // When building the PositioningContext for this cell, we want it to have the same
// configuration for whatever PositioningContext the contents are ultimately added to.
let collect_for_nearest_positioned_ancestor = parent_positioning_context
.collects_for_nearest_positioned_ancestor() ||
self.table.rows.get(row_index).map_or(false, |row| {
let row_group_collects_for_nearest_positioned_ancestor =
row.group_index.map_or(false, |group_index| {
self.table.row_groups[group_index]
.style
.establishes_containing_block_for_absolute_descendants()
});
row_group_collects_for_nearest_positioned_ancestor ||
row.style
.establishes_containing_block_for_absolute_descendants()
});
let mut cells_laid_out_row = Vec::new(); let mut cells_laid_out_row = Vec::new();
for (column_index, slot) in row.iter().enumerate() { let slots = &self.table.slots[row_index];
for (column_index, slot) in slots.iter().enumerate() {
let cell = match slot { let cell = match slot {
TableSlot::Cell(cell) => cell, TableSlot::Cell(cell) => cell,
_ => { _ => {
@ -1001,8 +1019,7 @@ impl<'a> TableLayout<'a> {
block_size: AuOrAuto::Auto, block_size: AuOrAuto::Auto,
style: &cell.style, style: &cell.style,
}; };
let collect_for_nearest_positioned_ancestor =
parent_positioning_context.collects_for_nearest_positioned_ancestor();
let mut positioning_context = let mut positioning_context =
PositioningContext::new_for_subtree(collect_for_nearest_positioned_ancestor); PositioningContext::new_for_subtree(collect_for_nearest_positioned_ancestor);
@ -1398,21 +1415,52 @@ impl<'a> TableLayout<'a> {
assert_eq!(self.table.size.width, self.distributed_column_widths.len()); assert_eq!(self.table.size.width, self.distributed_column_widths.len());
let mut baselines = Baselines::default(); let mut baselines = Baselines::default();
let mut fragments = Vec::new(); let mut table_fragments = Vec::new();
if self.table.size.width == 0 || self.table.size.height == 0 { if self.table.size.width == 0 || self.table.size.height == 0 {
return IndependentLayout { return IndependentLayout {
fragments, fragments: table_fragments,
content_block_size: self.final_table_height, content_block_size: self.final_table_height,
content_inline_size_for_table: Some(self.assignable_width), content_inline_size_for_table: Some(self.assignable_width),
baselines, baselines,
}; };
} }
let dimensions = TableAndTrackDimensions::new(&self); let table_and_track_dimensions = TableAndTrackDimensions::new(&self);
self.make_fragments_for_columns_rows_and_groups(&dimensions, &mut fragments); self.make_fragments_for_columns_and_column_groups(
&table_and_track_dimensions,
&mut table_fragments,
);
let mut row_group_fragment_layout = None;
for row_index in 0..self.table.size.height { for row_index in 0..self.table.size.height {
let table_row = &self.table.rows[row_index];
let mut row_fragment_layout =
RowFragmentLayout::new(table_row, row_index, &table_and_track_dimensions);
let old_row_group_index = row_group_fragment_layout
.as_ref()
.map(|layout: &RowGroupFragmentLayout| layout.index);
if table_row.group_index != old_row_group_index {
// First create the Fragment for any existing RowGroupFragmentLayout.
if let Some(old_row_group_layout) = row_group_fragment_layout.take() {
table_fragments.push(Fragment::Box(old_row_group_layout.finish(
layout_context,
positioning_context,
containing_block_for_children,
)));
}
// 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],
new_group_index,
&table_and_track_dimensions,
));
}
}
// From <https://drafts.csswg.org/css-align-3/#baseline-export> // From <https://drafts.csswg.org/css-align-3/#baseline-export>
// > If any cells in the row participate in first baseline/last baseline alignment along // > If any cells in the row participate in first baseline/last baseline alignment along
// > the inline axis, the first/last baseline set of the row is generated from their // > the inline axis, the first/last baseline set of the row is generated from their
@ -1423,86 +1471,57 @@ impl<'a> TableLayout<'a> {
// If any cell below has baseline alignment, these values will be overwritten, // If any cell below has baseline alignment, these values will be overwritten,
// but they are initialized to the content edge of the first row. // but they are initialized to the content edge of the first row.
if row_index == 0 { if row_index == 0 {
let row_end = dimensions.get_row_rect(0).max_block_position(); let row_end = table_and_track_dimensions
.get_row_rect(0)
.max_block_position();
baselines.first = Some(row_end); baselines.first = Some(row_end);
baselines.last = Some(row_end); baselines.last = Some(row_end);
} }
for column_index in 0..self.table.size.width { let column_indices = 0..self.table.size.width.clone();
let layout = match self.cells_laid_out[row_index][column_index].take() { row_fragment_layout.fragments.reserve(self.table.size.width);
Some(layout) => layout, for column_index in column_indices {
None => { // The PositioningContext for cells is, in order or preference, the PositioningContext of the row,
continue; // the PositioningContext of the row group, or the PositioningContext of the table.
}, let row_group_positioning_context = row_group_fragment_layout
}; .as_mut()
.and_then(|layout| layout.positioning_context.as_mut());
let positioning_context_for_cells = row_fragment_layout
.positioning_context
.as_mut()
.or(row_group_positioning_context)
.unwrap_or(positioning_context);
let cell = match self.table.slots[row_index][column_index] { self.do_final_cell_layout(
TableSlot::Cell(ref cell) => cell, row_index,
_ => { column_index,
warn!("Did not find a non-spanned cell at index with layout."); &table_and_track_dimensions,
continue; &row_fragment_layout.rect,
}, positioning_context_for_cells,
}; &mut baselines,
&mut row_fragment_layout.fragments,
let cell_rect = dimensions.get_cell_rect(
TableSlotCoordinates::new(column_index, row_index),
cell.rowspan,
cell.colspan,
); );
// If this cell has baseline alignment, it can adjust the table's overall baseline.
let row_baseline = self.row_baselines[row_index];
if cell.effective_vertical_align() == VerticalAlignKeyword::Baseline {
let baseline = cell_rect.start_corner.block + row_baseline;
if row_index == 0 {
baselines.first = Some(baseline);
}
baselines.last = Some(baseline);
}
let mut fragment =
cell.create_fragment(layout, cell_rect, row_baseline, positioning_context);
let column = self.table.columns.get(column_index);
let column_group = column
.and_then(|column| column.group_index)
.and_then(|index| self.table.column_groups.get(index));
if let Some(column_group) = column_group {
fragment.add_extra_background(ExtraBackground {
style: column_group.style.clone(),
rect: dimensions.get_column_group_rect(column_group),
})
}
if let Some(column) = column {
if !column.is_anonymous {
fragment.add_extra_background(ExtraBackground {
style: column.style.clone(),
rect: dimensions.get_column_rect(column_index),
})
}
}
let row = self.table.rows.get(row_index);
let row_group = row
.and_then(|row| row.group_index)
.and_then(|index| self.table.row_groups.get(index));
if let Some(row_group) = row_group {
fragment.add_extra_background(ExtraBackground {
style: row_group.style.clone(),
rect: dimensions.get_row_group_rect(row_group),
})
}
if let Some(row) = row {
fragment.add_extra_background(ExtraBackground {
style: row.style.clone(),
rect: dimensions.get_row_rect(row_index),
})
}
fragments.push(Fragment::Box(fragment));
} }
let row_fragment = Fragment::Box(row_fragment_layout.finish(
layout_context,
positioning_context,
containing_block_for_children,
&mut row_group_fragment_layout,
));
match row_group_fragment_layout.as_mut() {
Some(layout) => layout.fragments.push(row_fragment),
None => table_fragments.push(row_fragment),
}
}
if let Some(row_group_layout) = row_group_fragment_layout.take() {
table_fragments.push(Fragment::Box(row_group_layout.finish(
layout_context,
positioning_context,
containing_block_for_children,
)));
} }
if self.table.anonymous { if self.table.anonymous {
@ -1511,14 +1530,109 @@ impl<'a> TableLayout<'a> {
} }
IndependentLayout { IndependentLayout {
fragments, fragments: table_fragments,
content_block_size: dimensions.table_rect.max_block_position(), content_block_size: table_and_track_dimensions.table_rect.max_block_position(),
content_inline_size_for_table: Some(dimensions.table_rect.max_inline_position()), content_inline_size_for_table: Some(
table_and_track_dimensions.table_rect.max_inline_position(),
),
baselines, baselines,
} }
} }
fn make_fragments_for_columns_rows_and_groups( fn do_final_cell_layout(
&mut self,
row_index: usize,
column_index: usize,
dimensions: &TableAndTrackDimensions,
row_rect: &LogicalRect<Au>,
positioning_context: &mut PositioningContext,
baselines: &mut Baselines,
cell_fragments: &mut Vec<Fragment>,
) {
let layout = match self.cells_laid_out[row_index][column_index].take() {
Some(layout) => layout,
None => {
return;
},
};
let cell = match self.table.slots[row_index][column_index] {
TableSlot::Cell(ref cell) => cell,
_ => {
warn!("Did not find a non-spanned cell at index with layout.");
return;
},
};
let row_block_offset = row_rect.start_corner.block;
let row_baseline = self.row_baselines[row_index];
if cell.effective_vertical_align() == VerticalAlignKeyword::Baseline {
let baseline = row_block_offset + row_baseline;
if row_index == 0 {
baselines.first = Some(baseline);
}
baselines.last = Some(baseline);
}
let mut row_relative_cell_rect = dimensions.get_cell_rect(
TableSlotCoordinates::new(column_index, row_index),
cell.rowspan,
cell.colspan,
);
row_relative_cell_rect.start_corner =
&row_relative_cell_rect.start_corner - &row_rect.start_corner;
let mut fragment = cell.create_fragment(
layout,
row_relative_cell_rect,
row_baseline,
positioning_context,
);
let column = self.table.columns.get(column_index);
let column_group = column
.and_then(|column| column.group_index)
.and_then(|index| self.table.column_groups.get(index));
if let Some(column_group) = column_group {
let mut rect = dimensions.get_column_group_rect(column_group);
rect.start_corner -= row_rect.start_corner;
fragment.add_extra_background(ExtraBackground {
style: column_group.style.clone(),
rect,
})
}
if let Some(column) = column {
if !column.is_anonymous {
let mut rect = dimensions.get_column_rect(column_index);
rect.start_corner -= row_rect.start_corner;
fragment.add_extra_background(ExtraBackground {
style: column.style.clone(),
rect,
})
}
}
let row = self.table.rows.get(row_index);
let row_group = row
.and_then(|row| row.group_index)
.and_then(|index| self.table.row_groups.get(index));
if let Some(row_group) = row_group {
let mut rect = dimensions.get_row_group_rect(row_group);
rect.start_corner -= row_rect.start_corner;
fragment.add_extra_background(ExtraBackground {
style: row_group.style.clone(),
rect,
})
}
if let Some(row) = row {
let mut rect = row_rect.clone();
rect.start_corner = LogicalVec2::zero();
fragment.add_extra_background(ExtraBackground {
style: row.style.clone(),
rect,
})
}
cell_fragments.push(Fragment::Box(fragment));
// If this cell has baseline alignment, it can adjust the table's overall baseline.
}
fn make_fragments_for_columns_and_column_groups(
&mut self, &mut self,
dimensions: &TableAndTrackDimensions, dimensions: &TableAndTrackDimensions,
fragments: &mut Vec<Fragment>, fragments: &mut Vec<Fragment>,
@ -1540,27 +1654,129 @@ impl<'a> TableLayout<'a> {
column.style.clone(), column.style.clone(),
))); )));
} }
for row_group in self.table.row_groups.iter() {
if !row_group.is_empty() {
fragments.push(Fragment::Positioning(PositioningFragment::new_empty(
row_group.base_fragment_info,
dimensions.get_row_group_rect(row_group).into(),
row_group.style.clone(),
)));
}
}
for (row_index, row) in self.table.rows.iter().enumerate() {
fragments.push(Fragment::Positioning(PositioningFragment::new_empty(
row.base_fragment_info,
dimensions.get_row_rect(row_index).into(),
row.style.clone(),
)));
}
} }
} }
struct RowFragmentLayout<'a> {
row: &'a TableTrack,
rect: LogicalRect<Au>,
positioning_context: Option<PositioningContext>,
fragments: Vec<Fragment>,
}
impl<'a> RowFragmentLayout<'a> {
fn new(table_row: &'a TableTrack, index: usize, dimensions: &TableAndTrackDimensions) -> Self {
Self {
row: table_row,
rect: dimensions.get_row_rect(index),
positioning_context: PositioningContext::new_for_style(&table_row.style),
fragments: Vec::new(),
}
}
fn finish(
mut self,
layout_context: &LayoutContext,
table_positioning_context: &mut PositioningContext,
containing_block: &ContainingBlock,
row_group_fragment_layout: &mut Option<RowGroupFragmentLayout>,
) -> BoxFragment {
let mut row_rect: LogicalRect<Length> = self.rect.into();
if self.positioning_context.is_some() {
row_rect.start_corner += relative_adjustement(&self.row.style, containing_block);
}
if let Some(ref row_group_layout) = row_group_fragment_layout {
let row_group_start_corner: LogicalVec2<Length> =
row_group_layout.rect.start_corner.into();
row_rect.start_corner -= row_group_start_corner;
}
let mut row_fragment = BoxFragment::new(
self.row.base_fragment_info,
self.row.style.clone(),
self.fragments,
row_rect,
LogicalSides::zero(), /* padding */
LogicalSides::zero(), /* border */
LogicalSides::zero(), /* margin */
None, /* clearance */
CollapsedBlockMargins::zero(),
);
row_fragment.set_does_not_paint_background();
if let Some(mut row_positioning_context) = self.positioning_context.take() {
row_positioning_context.layout_collected_children(layout_context, &mut row_fragment);
let positioning_context = row_group_fragment_layout
.as_mut()
.and_then(|layout| layout.positioning_context.as_mut())
.unwrap_or(table_positioning_context);
positioning_context.append(row_positioning_context);
}
row_fragment
}
}
struct RowGroupFragmentLayout {
base_fragment_info: BaseFragmentInfo,
style: Arc<ComputedValues>,
rect: LogicalRect<Au>,
positioning_context: Option<PositioningContext>,
index: usize,
fragments: Vec<Fragment>,
}
impl RowGroupFragmentLayout {
fn new(
row_group: &TableTrackGroup,
index: usize,
dimensions: &TableAndTrackDimensions,
) -> Self {
let rect = dimensions.get_row_group_rect(row_group);
Self {
base_fragment_info: row_group.base_fragment_info,
style: row_group.style.clone(),
rect,
positioning_context: PositioningContext::new_for_style(&row_group.style),
index,
fragments: Vec::new(),
}
}
fn finish(
mut self,
layout_context: &LayoutContext,
table_positioning_context: &mut PositioningContext,
containing_block: &ContainingBlock,
) -> BoxFragment {
let mut content_rect: LogicalRect<Length> = self.rect.into();
if self.positioning_context.is_some() {
content_rect.start_corner += relative_adjustement(&self.style, containing_block);
}
let mut row_group_fragment = BoxFragment::new(
self.base_fragment_info,
self.style,
self.fragments,
content_rect,
LogicalSides::zero(), /* padding */
LogicalSides::zero(), /* border */
LogicalSides::zero(), /* margin */
None, /* clearance */
CollapsedBlockMargins::zero(),
);
row_group_fragment.set_does_not_paint_background();
if let Some(mut row_positioning_context) = self.positioning_context.take() {
row_positioning_context
.layout_collected_children(layout_context, &mut row_group_fragment);
table_positioning_context.append(row_positioning_context);
}
row_group_fragment
}
}
struct TableAndTrackDimensions { struct TableAndTrackDimensions {
/// The rect of the full table, not counting for borders, padding, and margin. /// The rect of the full table, not counting for borders, padding, and margin.
table_rect: LogicalRect<Au>, table_rect: LogicalRect<Au>,

View file

@ -0,0 +1,2 @@
[row-visibility-002.xht]
expected: FAIL

View file

@ -1,2 +0,0 @@
[position-relative-012.html]
expected: FAIL

View file

@ -16,3 +16,6 @@
[Replaced elements outside a table cannot be table-row and are considered inline -- input=file elements] [Replaced elements outside a table cannot be table-row and are considered inline -- input=file elements]
expected: FAIL expected: FAIL
[Replaced elements outside a table cannot be table-row-group and are considered inline -- input=file elements]
expected: FAIL

View file

@ -1,2 +0,0 @@
[section-no-tbody-fixed-distribution.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[section-no-tbody-percent-distribution.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[transform-transformable-table-footer-group.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[transform-transformable-table-header-group.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[transform-transformable-table-row-group.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[transform-transformable-table-row.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[transform-transformed-tbody-contains-fixed-position.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[transform-transformed-tfoot-contains-fixed-position.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[transform-transformed-thead-contains-fixed-position.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[transform-transformed-tr-contains-fixed-position.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[transform-transformed-tr-percent-height-child.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[text-overflow-025.html]
expected: FAIL

View file

@ -4,3 +4,9 @@
[elementsFromPoint for points inside cells in a flipped (writing-mode:vertical-lr) table] [elementsFromPoint for points inside cells in a flipped (writing-mode:vertical-lr) table]
expected: FAIL expected: FAIL
[elementsFromPoint for points inside table cells]
expected: FAIL
[elementsFromPoint for points between table cells]
expected: FAIL

View file

@ -0,0 +1,2 @@
[tr-transform-and-will-change.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[table-cell-width-calculation-abspos.html]
expected: FAIL