mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +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
|
@ -40,7 +40,7 @@ pub struct LogicalRect<T> {
|
||||||
pub size: LogicalVec2<T>,
|
pub size: LogicalVec2<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
pub struct LogicalSides<T> {
|
pub struct LogicalSides<T> {
|
||||||
pub inline_start: T,
|
pub inline_start: T,
|
||||||
pub inline_end: T,
|
pub inline_end: T,
|
||||||
|
|
|
@ -45,11 +45,12 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
fn detailed_layout_info(
|
fn detailed_layout_info(
|
||||||
border_style_color: Option<PhysicalSides<BorderStyleColor>>,
|
border_style_color: Option<LogicalSides<BorderStyleColor>>,
|
||||||
|
writing_mode: WritingMode,
|
||||||
) -> Option<SpecificLayoutInfo> {
|
) -> Option<SpecificLayoutInfo> {
|
||||||
Some(SpecificLayoutInfo::TableOrTableCell(Box::new(
|
Some(SpecificLayoutInfo::TableOrTableCell(Box::new(
|
||||||
SpecificTableOrTableCellInfo {
|
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) {
|
fn max_assign(&mut self, other: &Self) {
|
||||||
if *self < other {
|
if *self < *other {
|
||||||
*self = other;
|
*self = other.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,13 +173,25 @@ impl PartialOrd for CollapsedBorder {
|
||||||
|
|
||||||
impl Eq for CollapsedBorder {}
|
impl Eq for CollapsedBorder {}
|
||||||
|
|
||||||
/// The calculated collapsed borders.
|
/// Represents a piecewise sequence of collapsed borders along a line.
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
struct CollapsedBorders {
|
struct CollapsedBorderLine {
|
||||||
block: Vec<CollapsedBorder>,
|
max_width: Au,
|
||||||
inline: Vec<CollapsedBorder>,
|
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
|
/// A helper struct that performs the layout of the box tree version
|
||||||
/// of a table into the fragment tree version. This implements
|
/// of a table into the fragment tree version. This implements
|
||||||
/// <https://drafts.csswg.org/css-tables/#table-layout-algorithm>
|
/// <https://drafts.csswg.org/css-tables/#table-layout-algorithm>
|
||||||
|
@ -279,14 +292,13 @@ impl<'a> TableLayout<'a> {
|
||||||
.percentages_relative_to(Au::zero());
|
.percentages_relative_to(Au::zero());
|
||||||
|
|
||||||
let border = self
|
let border = self
|
||||||
.get_collapsed_borders_for_cell(
|
.get_collapsed_border_widths_for_area(LogicalSides {
|
||||||
cell,
|
inline_start: column_index,
|
||||||
TableSlotCoordinates::new(column_index, row_index),
|
inline_end: column_index + cell.colspan,
|
||||||
)
|
block_start: row_index,
|
||||||
.map_or_else(
|
block_end: row_index + cell.rowspan,
|
||||||
|| cell.base.style.border_width(writing_mode),
|
})
|
||||||
|(border, _)| border,
|
.unwrap_or_else(|| cell.base.style.border_width(writing_mode));
|
||||||
);
|
|
||||||
|
|
||||||
let padding_border_sums = LogicalVec2 {
|
let padding_border_sums = LogicalVec2 {
|
||||||
inline: padding.inline_sum() + border.inline_sum(),
|
inline: padding.inline_sum() + border.inline_sum(),
|
||||||
|
@ -1195,22 +1207,23 @@ impl<'a> TableLayout<'a> {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
let coordinates = TableSlotCoordinates::new(column_index, row_index);
|
let area = LogicalSides {
|
||||||
let (border, detailed_layout_info) =
|
inline_start: column_index,
|
||||||
match self.get_collapsed_borders_for_cell(cell, coordinates) {
|
inline_end: column_index + cell.colspan,
|
||||||
Some((border_width, border_style_color)) => {
|
block_start: row_index,
|
||||||
let border_style_color = border_style_color
|
block_end: row_index + cell.rowspan,
|
||||||
.to_physical(self.table.style.writing_mode);
|
};
|
||||||
(border_width, detailed_layout_info(Some(border_style_color)))
|
let detailed_layout_info = detailed_layout_info(
|
||||||
},
|
self.get_collapsed_border_style_colors_for_area(area),
|
||||||
None => (
|
self.table.style.writing_mode,
|
||||||
cell.base.style.border_width(
|
);
|
||||||
containing_block_for_table.style.writing_mode,
|
let border = self
|
||||||
),
|
.get_collapsed_border_widths_for_area(area)
|
||||||
None,
|
.unwrap_or_else(|| {
|
||||||
),
|
cell.base
|
||||||
};
|
.style
|
||||||
|
.border_width(containing_block_for_table.style.writing_mode)
|
||||||
|
});
|
||||||
let padding: LogicalSides<Au> = cell
|
let padding: LogicalSides<Au> = cell
|
||||||
.base
|
.base
|
||||||
.style
|
.style
|
||||||
|
@ -1861,20 +1874,13 @@ impl<'a> TableLayout<'a> {
|
||||||
assert_eq!(self.table.size.height, self.row_sizes.len());
|
assert_eq!(self.table.size.height, self.row_sizes.len());
|
||||||
assert_eq!(self.table.size.width, self.distributed_column_widths.len());
|
assert_eq!(self.table.size.width, self.distributed_column_widths.len());
|
||||||
|
|
||||||
let border_style_color = self.collapsed_borders.as_ref().map(|collapsed_borders| {
|
let border_style_color = self.get_collapsed_border_style_colors_for_area(LogicalSides {
|
||||||
LogicalSides {
|
inline_start: 0,
|
||||||
inline_start: collapsed_borders.inline[0].style_color.clone(),
|
inline_end: self.table.size.width,
|
||||||
inline_end: collapsed_borders.inline[self.table.size.width]
|
block_start: 0,
|
||||||
.style_color
|
block_end: self.table.size.height,
|
||||||
.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 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 {
|
if self.table.size.width == 0 && self.table.size.height == 0 {
|
||||||
let content_rect = LogicalRect {
|
let content_rect = LogicalRect {
|
||||||
|
@ -2211,17 +2217,29 @@ impl<'a> TableLayout<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut collapsed_borders = CollapsedBorders {
|
let mut collapsed_borders = CollapsedBorders {
|
||||||
block: vec![Default::default(); self.table.size.height + 1],
|
block: vec![
|
||||||
inline: vec![Default::default(); self.table.size.width + 1],
|
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 =
|
let mut apply_border =
|
||||||
|style: &ComputedValues, block: &Range<usize>, inline: &Range<usize>| {
|
|style: &ComputedValues, block: &Range<usize>, inline: &Range<usize>| {
|
||||||
let border = CollapsedBorder::from_style(style, writing_mode);
|
let border = CollapsedBorder::from_style(style, writing_mode);
|
||||||
collapsed_borders.block[block.start].max_assign(border.block_start);
|
collapsed_borders.block[block.start].max_assign(&border.block_start, inline);
|
||||||
collapsed_borders.block[block.end].max_assign(border.block_end);
|
collapsed_borders.block[block.end].max_assign(&border.block_end, inline);
|
||||||
collapsed_borders.inline[inline.start].max_assign(border.inline_start);
|
collapsed_borders.inline[inline.start].max_assign(&border.inline_start, block);
|
||||||
collapsed_borders.inline[inline.end].max_assign(border.inline_end);
|
collapsed_borders.inline[inline.end].max_assign(&border.inline_end, block);
|
||||||
};
|
};
|
||||||
let all_rows = 0..self.table.size.height;
|
let all_rows = 0..self.table.size.height;
|
||||||
let all_columns = 0..self.table.size.width;
|
let all_columns = 0..self.table.size.width;
|
||||||
|
@ -2256,47 +2274,61 @@ impl<'a> TableLayout<'a> {
|
||||||
self.collapsed_borders = Some(collapsed_borders);
|
self.collapsed_borders = Some(collapsed_borders);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_collapsed_borders_for_cell(
|
fn get_collapsed_border_widths_for_area(
|
||||||
&self,
|
&self,
|
||||||
cell: &TableSlotCell,
|
area: LogicalSides<usize>,
|
||||||
coordinates: TableSlotCoordinates,
|
) -> Option<LogicalSides<Au>> {
|
||||||
) -> Option<(LogicalSides<Au>, LogicalSides<BorderStyleColor>)> {
|
|
||||||
let collapsed_borders = self.collapsed_borders.as_ref()?;
|
let collapsed_borders = self.collapsed_borders.as_ref()?;
|
||||||
let end_x = coordinates.x + cell.colspan;
|
let inline_start = &collapsed_borders.inline[area.inline_start];
|
||||||
let end_y = coordinates.y + cell.rowspan;
|
let inline_end = &collapsed_borders.inline[area.inline_end];
|
||||||
let inline_start = &collapsed_borders.inline[coordinates.x];
|
let block_start = &collapsed_borders.block[area.block_start];
|
||||||
let inline_end = &collapsed_borders.inline[end_x];
|
let block_end = &collapsed_borders.block[area.block_end];
|
||||||
let block_start = &collapsed_borders.block[coordinates.y];
|
Some(LogicalSides {
|
||||||
let block_end = &collapsed_borders.block[end_y];
|
inline_start: if area.inline_start == 0 {
|
||||||
let border_width = LogicalSides {
|
inline_start.max_width - self.pbm.border.inline_start
|
||||||
inline_start: if coordinates.x == 0 {
|
|
||||||
inline_start.width - self.pbm.border.inline_start
|
|
||||||
} else {
|
} else {
|
||||||
inline_start.width / 2
|
inline_start.max_width / 2
|
||||||
},
|
},
|
||||||
inline_end: if end_x == self.table.size.width {
|
inline_end: if area.inline_end == self.table.size.width {
|
||||||
inline_end.width - self.pbm.border.inline_end
|
inline_end.max_width - self.pbm.border.inline_end
|
||||||
} else {
|
} else {
|
||||||
inline_end.width / 2
|
inline_end.max_width / 2
|
||||||
},
|
},
|
||||||
block_start: if coordinates.y == 0 {
|
block_start: if area.block_start == 0 {
|
||||||
block_start.width - self.pbm.border.block_start
|
block_start.max_width - self.pbm.border.block_start
|
||||||
} else {
|
} else {
|
||||||
block_start.width / 2
|
block_start.max_width / 2
|
||||||
},
|
},
|
||||||
block_end: if end_y == self.table.size.height {
|
block_end: if area.block_end == self.table.size.height {
|
||||||
block_end.width - self.pbm.border.block_end
|
block_end.max_width - self.pbm.border.block_end
|
||||||
} else {
|
} 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(),
|
fn get_collapsed_border_style_colors_for_area(
|
||||||
block_start: block_start.style_color.clone(),
|
&self,
|
||||||
block_end: block_end.style_color.clone(),
|
area: LogicalSides<usize>,
|
||||||
};
|
) -> Option<LogicalSides<BorderStyleColor>> {
|
||||||
Some((border_width, border_style_color))
|
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(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[border-bottom-applies-to-006.xht]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[border-bottom-color-applies-to-006.xht]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[border-bottom-width-applies-to-006.xht]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[border-top-applies-to-006.xht]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[border-top-color-applies-to-006.xht]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[border-top-width-applies-to-006.xht]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[border-collapse-dynamic-cell-002.xht]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[collapsed-border-remove-cell.html]
|
|
||||||
expected: FAIL
|
|
Loading…
Add table
Add a link
Reference in a new issue