|
|
|
@ -45,11 +45,12 @@ use crate::{
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
fn detailed_layout_info(
|
|
|
|
|
border_style_color: Option<PhysicalSides<BorderStyleColor>>,
|
|
|
|
|
border_style_color: Option<LogicalSides<BorderStyleColor>>,
|
|
|
|
|
writing_mode: WritingMode,
|
|
|
|
|
) -> Option<SpecificLayoutInfo> {
|
|
|
|
|
Some(SpecificLayoutInfo::TableOrTableCell(Box::new(
|
|
|
|
|
SpecificTableOrTableCellInfo {
|
|
|
|
|
border_style_color: border_style_color?,
|
|
|
|
|
border_style_color: border_style_color?.to_physical(writing_mode),
|
|
|
|
|
},
|
|
|
|
|
)))
|
|
|
|
|
}
|
|
|
|
@ -131,9 +132,9 @@ impl CollapsedBorder {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn max_assign(&mut self, other: Self) {
|
|
|
|
|
if *self < other {
|
|
|
|
|
*self = other;
|
|
|
|
|
fn max_assign(&mut self, other: &Self) {
|
|
|
|
|
if *self < *other {
|
|
|
|
|
*self = other.clone();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -172,13 +173,25 @@ impl PartialOrd for CollapsedBorder {
|
|
|
|
|
|
|
|
|
|
impl Eq for CollapsedBorder {}
|
|
|
|
|
|
|
|
|
|
/// The calculated collapsed borders.
|
|
|
|
|
/// Represents a piecewise sequence of collapsed borders along a line.
|
|
|
|
|
#[derive(Clone, Debug, Default)]
|
|
|
|
|
struct CollapsedBorders {
|
|
|
|
|
block: Vec<CollapsedBorder>,
|
|
|
|
|
inline: Vec<CollapsedBorder>,
|
|
|
|
|
struct CollapsedBorderLine {
|
|
|
|
|
max_width: Au,
|
|
|
|
|
list: Vec<CollapsedBorder>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl CollapsedBorderLine {
|
|
|
|
|
fn max_assign(&mut self, collapsed_border: &CollapsedBorder, range: &Range<usize>) {
|
|
|
|
|
self.max_width.max_assign(collapsed_border.width);
|
|
|
|
|
for index in range.clone() {
|
|
|
|
|
self.list[index].max_assign(collapsed_border)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The calculated collapsed borders.
|
|
|
|
|
type CollapsedBorders = LogicalVec2<Vec<CollapsedBorderLine>>;
|
|
|
|
|
|
|
|
|
|
/// A helper struct that performs the layout of the box tree version
|
|
|
|
|
/// of a table into the fragment tree version. This implements
|
|
|
|
|
/// <https://drafts.csswg.org/css-tables/#table-layout-algorithm>
|
|
|
|
@ -279,14 +292,13 @@ impl<'a> TableLayout<'a> {
|
|
|
|
|
.percentages_relative_to(Au::zero());
|
|
|
|
|
|
|
|
|
|
let border = self
|
|
|
|
|
.get_collapsed_borders_for_cell(
|
|
|
|
|
cell,
|
|
|
|
|
TableSlotCoordinates::new(column_index, row_index),
|
|
|
|
|
)
|
|
|
|
|
.map_or_else(
|
|
|
|
|
|| cell.base.style.border_width(writing_mode),
|
|
|
|
|
|(border, _)| border,
|
|
|
|
|
);
|
|
|
|
|
.get_collapsed_border_widths_for_area(LogicalSides {
|
|
|
|
|
inline_start: column_index,
|
|
|
|
|
inline_end: column_index + cell.colspan,
|
|
|
|
|
block_start: row_index,
|
|
|
|
|
block_end: row_index + cell.rowspan,
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or_else(|| cell.base.style.border_width(writing_mode));
|
|
|
|
|
|
|
|
|
|
let padding_border_sums = LogicalVec2 {
|
|
|
|
|
inline: padding.inline_sum() + border.inline_sum(),
|
|
|
|
@ -1195,22 +1207,23 @@ impl<'a> TableLayout<'a> {
|
|
|
|
|
return None;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let coordinates = TableSlotCoordinates::new(column_index, row_index);
|
|
|
|
|
let (border, detailed_layout_info) =
|
|
|
|
|
match self.get_collapsed_borders_for_cell(cell, coordinates) {
|
|
|
|
|
Some((border_width, border_style_color)) => {
|
|
|
|
|
let border_style_color = border_style_color
|
|
|
|
|
.to_physical(self.table.style.writing_mode);
|
|
|
|
|
(border_width, detailed_layout_info(Some(border_style_color)))
|
|
|
|
|
},
|
|
|
|
|
None => (
|
|
|
|
|
cell.base.style.border_width(
|
|
|
|
|
containing_block_for_table.style.writing_mode,
|
|
|
|
|
),
|
|
|
|
|
None,
|
|
|
|
|
),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let area = LogicalSides {
|
|
|
|
|
inline_start: column_index,
|
|
|
|
|
inline_end: column_index + cell.colspan,
|
|
|
|
|
block_start: row_index,
|
|
|
|
|
block_end: row_index + cell.rowspan,
|
|
|
|
|
};
|
|
|
|
|
let detailed_layout_info = detailed_layout_info(
|
|
|
|
|
self.get_collapsed_border_style_colors_for_area(area),
|
|
|
|
|
self.table.style.writing_mode,
|
|
|
|
|
);
|
|
|
|
|
let border = self
|
|
|
|
|
.get_collapsed_border_widths_for_area(area)
|
|
|
|
|
.unwrap_or_else(|| {
|
|
|
|
|
cell.base
|
|
|
|
|
.style
|
|
|
|
|
.border_width(containing_block_for_table.style.writing_mode)
|
|
|
|
|
});
|
|
|
|
|
let padding: LogicalSides<Au> = cell
|
|
|
|
|
.base
|
|
|
|
|
.style
|
|
|
|
@ -1861,20 +1874,13 @@ impl<'a> TableLayout<'a> {
|
|
|
|
|
assert_eq!(self.table.size.height, self.row_sizes.len());
|
|
|
|
|
assert_eq!(self.table.size.width, self.distributed_column_widths.len());
|
|
|
|
|
|
|
|
|
|
let border_style_color = self.collapsed_borders.as_ref().map(|collapsed_borders| {
|
|
|
|
|
LogicalSides {
|
|
|
|
|
inline_start: collapsed_borders.inline[0].style_color.clone(),
|
|
|
|
|
inline_end: collapsed_borders.inline[self.table.size.width]
|
|
|
|
|
.style_color
|
|
|
|
|
.clone(),
|
|
|
|
|
block_start: collapsed_borders.block[0].style_color.clone(),
|
|
|
|
|
block_end: collapsed_borders.block[self.table.size.height]
|
|
|
|
|
.style_color
|
|
|
|
|
.clone(),
|
|
|
|
|
}
|
|
|
|
|
.to_physical(table_writing_mode)
|
|
|
|
|
let border_style_color = self.get_collapsed_border_style_colors_for_area(LogicalSides {
|
|
|
|
|
inline_start: 0,
|
|
|
|
|
inline_end: self.table.size.width,
|
|
|
|
|
block_start: 0,
|
|
|
|
|
block_end: self.table.size.height,
|
|
|
|
|
});
|
|
|
|
|
let detailed_layout_info = detailed_layout_info(border_style_color);
|
|
|
|
|
let detailed_layout_info = detailed_layout_info(border_style_color, table_writing_mode);
|
|
|
|
|
|
|
|
|
|
if self.table.size.width == 0 && self.table.size.height == 0 {
|
|
|
|
|
let content_rect = LogicalRect {
|
|
|
|
@ -2211,17 +2217,29 @@ impl<'a> TableLayout<'a> {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut collapsed_borders = CollapsedBorders {
|
|
|
|
|
block: vec![Default::default(); self.table.size.height + 1],
|
|
|
|
|
inline: vec![Default::default(); self.table.size.width + 1],
|
|
|
|
|
block: vec![
|
|
|
|
|
CollapsedBorderLine {
|
|
|
|
|
max_width: Au::zero(),
|
|
|
|
|
list: vec![Default::default(); self.table.size.width],
|
|
|
|
|
};
|
|
|
|
|
self.table.size.height + 1
|
|
|
|
|
],
|
|
|
|
|
inline: vec![
|
|
|
|
|
CollapsedBorderLine {
|
|
|
|
|
max_width: Au::zero(),
|
|
|
|
|
list: vec![Default::default(); self.table.size.height],
|
|
|
|
|
};
|
|
|
|
|
self.table.size.width + 1
|
|
|
|
|
],
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let mut apply_border =
|
|
|
|
|
|style: &ComputedValues, block: &Range<usize>, inline: &Range<usize>| {
|
|
|
|
|
let border = CollapsedBorder::from_style(style, writing_mode);
|
|
|
|
|
collapsed_borders.block[block.start].max_assign(border.block_start);
|
|
|
|
|
collapsed_borders.block[block.end].max_assign(border.block_end);
|
|
|
|
|
collapsed_borders.inline[inline.start].max_assign(border.inline_start);
|
|
|
|
|
collapsed_borders.inline[inline.end].max_assign(border.inline_end);
|
|
|
|
|
collapsed_borders.block[block.start].max_assign(&border.block_start, inline);
|
|
|
|
|
collapsed_borders.block[block.end].max_assign(&border.block_end, inline);
|
|
|
|
|
collapsed_borders.inline[inline.start].max_assign(&border.inline_start, block);
|
|
|
|
|
collapsed_borders.inline[inline.end].max_assign(&border.inline_end, block);
|
|
|
|
|
};
|
|
|
|
|
let all_rows = 0..self.table.size.height;
|
|
|
|
|
let all_columns = 0..self.table.size.width;
|
|
|
|
@ -2256,47 +2274,61 @@ impl<'a> TableLayout<'a> {
|
|
|
|
|
self.collapsed_borders = Some(collapsed_borders);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_collapsed_borders_for_cell(
|
|
|
|
|
fn get_collapsed_border_widths_for_area(
|
|
|
|
|
&self,
|
|
|
|
|
cell: &TableSlotCell,
|
|
|
|
|
coordinates: TableSlotCoordinates,
|
|
|
|
|
) -> Option<(LogicalSides<Au>, LogicalSides<BorderStyleColor>)> {
|
|
|
|
|
area: LogicalSides<usize>,
|
|
|
|
|
) -> Option<LogicalSides<Au>> {
|
|
|
|
|
let collapsed_borders = self.collapsed_borders.as_ref()?;
|
|
|
|
|
let end_x = coordinates.x + cell.colspan;
|
|
|
|
|
let end_y = coordinates.y + cell.rowspan;
|
|
|
|
|
let inline_start = &collapsed_borders.inline[coordinates.x];
|
|
|
|
|
let inline_end = &collapsed_borders.inline[end_x];
|
|
|
|
|
let block_start = &collapsed_borders.block[coordinates.y];
|
|
|
|
|
let block_end = &collapsed_borders.block[end_y];
|
|
|
|
|
let border_width = LogicalSides {
|
|
|
|
|
inline_start: if coordinates.x == 0 {
|
|
|
|
|
inline_start.width - self.pbm.border.inline_start
|
|
|
|
|
let inline_start = &collapsed_borders.inline[area.inline_start];
|
|
|
|
|
let inline_end = &collapsed_borders.inline[area.inline_end];
|
|
|
|
|
let block_start = &collapsed_borders.block[area.block_start];
|
|
|
|
|
let block_end = &collapsed_borders.block[area.block_end];
|
|
|
|
|
Some(LogicalSides {
|
|
|
|
|
inline_start: if area.inline_start == 0 {
|
|
|
|
|
inline_start.max_width - self.pbm.border.inline_start
|
|
|
|
|
} else {
|
|
|
|
|
inline_start.width / 2
|
|
|
|
|
inline_start.max_width / 2
|
|
|
|
|
},
|
|
|
|
|
inline_end: if end_x == self.table.size.width {
|
|
|
|
|
inline_end.width - self.pbm.border.inline_end
|
|
|
|
|
inline_end: if area.inline_end == self.table.size.width {
|
|
|
|
|
inline_end.max_width - self.pbm.border.inline_end
|
|
|
|
|
} else {
|
|
|
|
|
inline_end.width / 2
|
|
|
|
|
inline_end.max_width / 2
|
|
|
|
|
},
|
|
|
|
|
block_start: if coordinates.y == 0 {
|
|
|
|
|
block_start.width - self.pbm.border.block_start
|
|
|
|
|
block_start: if area.block_start == 0 {
|
|
|
|
|
block_start.max_width - self.pbm.border.block_start
|
|
|
|
|
} else {
|
|
|
|
|
block_start.width / 2
|
|
|
|
|
block_start.max_width / 2
|
|
|
|
|
},
|
|
|
|
|
block_end: if end_y == self.table.size.height {
|
|
|
|
|
block_end.width - self.pbm.border.block_end
|
|
|
|
|
block_end: if area.block_end == self.table.size.height {
|
|
|
|
|
block_end.max_width - self.pbm.border.block_end
|
|
|
|
|
} else {
|
|
|
|
|
block_end.width / 2
|
|
|
|
|
block_end.max_width / 2
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
let border_style_color = LogicalSides {
|
|
|
|
|
inline_start: inline_start.style_color.clone(),
|
|
|
|
|
inline_end: inline_end.style_color.clone(),
|
|
|
|
|
block_start: block_start.style_color.clone(),
|
|
|
|
|
block_end: block_end.style_color.clone(),
|
|
|
|
|
};
|
|
|
|
|
Some((border_width, border_style_color))
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_collapsed_border_style_colors_for_area(
|
|
|
|
|
&self,
|
|
|
|
|
area: LogicalSides<usize>,
|
|
|
|
|
) -> Option<LogicalSides<BorderStyleColor>> {
|
|
|
|
|
let collapsed_borders = self.collapsed_borders.as_ref()?;
|
|
|
|
|
if self.table.size.width == 0 || self.table.size.height == 0 {
|
|
|
|
|
return Some(LogicalSides::default());
|
|
|
|
|
}
|
|
|
|
|
let inline_start = &collapsed_borders.inline[area.inline_start];
|
|
|
|
|
let inline_end = &collapsed_borders.inline[area.inline_end];
|
|
|
|
|
let block_start = &collapsed_borders.block[area.block_start];
|
|
|
|
|
let block_end = &collapsed_borders.block[area.block_end];
|
|
|
|
|
|
|
|
|
|
// This area may span multiple rows and columns, each of which can have different
|
|
|
|
|
// collapsed borders. However, we don't have support for one side of a box to have
|
|
|
|
|
// a piecewise border. Therefore, we just pick the first piece for the entire side.
|
|
|
|
|
Some(LogicalSides {
|
|
|
|
|
inline_start: inline_start.list[area.block_start].style_color.clone(),
|
|
|
|
|
inline_end: inline_end.list[area.block_start].style_color.clone(),
|
|
|
|
|
block_start: block_start.list[area.inline_start].style_color.clone(),
|
|
|
|
|
block_end: block_end.list[area.inline_start].style_color.clone(),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|