mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
layout: Allow different collapsed border style/color within a row/column (#35003)
We were previously using the same style and color for two collapsed borders sharing a coordinate. Now such a line of collapsed borders can be piecewise and have different colors and styles. This still doesn't add support for piecewise border widths. Also, since we are currently painting borders as part of the table and cell boxes, and a box side can't have a piecewise border, this patch only really works when: - There aren't spanning cells - The table has no assigned border (only the cells and tracks have it) Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
a1326a7cf6
commit
d58aa7fc04
10 changed files with 116 additions and 100 deletions
|
@ -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(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue