mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
Small improvements for table border collapse (#33452)
We were only collapsing the borders from adjacent cells. This patch also handles the borders from rows, row groups, columns, and column groups. Additionally, it takes the border style into account in order to decide which border wins. Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
679afe5195
commit
b12cebd1ac
11 changed files with 130 additions and 33 deletions
|
@ -16,7 +16,9 @@ use style::properties::ComputedValues;
|
|||
use style::servo::selector_parser::PseudoElement;
|
||||
use style::values::computed::basic_shape::ClipPath;
|
||||
use style::values::computed::image::Image as ComputedImageLayer;
|
||||
use style::values::computed::{AlignItems, LengthPercentage, NonNegativeLengthPercentage, Size};
|
||||
use style::values::computed::{
|
||||
AlignItems, BorderStyle, LengthPercentage, NonNegativeLengthPercentage, Size,
|
||||
};
|
||||
use style::values::generics::box_::Perspective;
|
||||
use style::values::generics::length::MaxSize;
|
||||
use style::values::generics::position::{GenericAspectRatio, PreferredRatio};
|
||||
|
@ -250,6 +252,8 @@ pub(crate) trait ComputedValuesExt {
|
|||
&self,
|
||||
containing_block_writing_mode: WritingMode,
|
||||
) -> LogicalSides<&LengthPercentage>;
|
||||
fn border_style(&self, containing_block_writing_mode: WritingMode)
|
||||
-> LogicalSides<BorderStyle>;
|
||||
fn border_width(&self, containing_block_writing_mode: WritingMode) -> LogicalSides<Au>;
|
||||
fn margin(
|
||||
&self,
|
||||
|
@ -553,6 +557,22 @@ impl ComputedValuesExt for ComputedValues {
|
|||
)
|
||||
}
|
||||
|
||||
fn border_style(
|
||||
&self,
|
||||
containing_block_writing_mode: WritingMode,
|
||||
) -> LogicalSides<BorderStyle> {
|
||||
let border = self.get_border();
|
||||
LogicalSides::from_physical(
|
||||
&PhysicalSides::new(
|
||||
border.border_top_style,
|
||||
border.border_right_style,
|
||||
border.border_bottom_style,
|
||||
border.border_left_style,
|
||||
),
|
||||
containing_block_writing_mode,
|
||||
)
|
||||
}
|
||||
|
||||
fn border_width(&self, containing_block_writing_mode: WritingMode) -> LogicalSides<Au> {
|
||||
let border = self.get_border();
|
||||
LogicalSides::from_physical(
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use core::cmp::Ordering;
|
||||
use std::ops::Range;
|
||||
|
||||
use app_units::{Au, MAX_AU};
|
||||
|
@ -16,7 +17,9 @@ use style::computed_values::table_layout::T as TableLayoutMode;
|
|||
use style::computed_values::visibility::T as Visibility;
|
||||
use style::logical_geometry::WritingMode;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::{LengthPercentage as ComputedLengthPercentage, Percentage};
|
||||
use style::values::computed::{
|
||||
BorderStyle, LengthPercentage as ComputedLengthPercentage, Percentage,
|
||||
};
|
||||
use style::values::generics::box_::{GenericVerticalAlign as VerticalAlign, VerticalAlignKeyword};
|
||||
use style::values::generics::length::GenericLengthPercentageOrAuto::{Auto, LengthPercentage};
|
||||
use style::Zero;
|
||||
|
@ -92,11 +95,79 @@ struct ColumnLayout {
|
|||
has_originating_cells: bool,
|
||||
}
|
||||
|
||||
/// A calculated collapsed border.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
struct CollapsedBorder {
|
||||
style: BorderStyle,
|
||||
width: Au,
|
||||
}
|
||||
|
||||
impl Default for CollapsedBorder {
|
||||
fn default() -> Self {
|
||||
Self::new(BorderStyle::None, Au::zero())
|
||||
}
|
||||
}
|
||||
|
||||
impl CollapsedBorder {
|
||||
fn new(style: BorderStyle, width: Au) -> Self {
|
||||
Self { style, width }
|
||||
}
|
||||
|
||||
fn from_style(style: &ComputedValues, writing_mode: WritingMode) -> LogicalSides<Self> {
|
||||
let border_style = style.border_style(writing_mode);
|
||||
let border_width = style.border_width(writing_mode);
|
||||
LogicalSides {
|
||||
inline_start: Self::new(border_style.inline_start, border_width.inline_start),
|
||||
inline_end: Self::new(border_style.inline_end, border_width.inline_end),
|
||||
block_start: Self::new(border_style.block_start, border_width.block_start),
|
||||
block_end: Self::new(border_style.block_end, border_width.block_end),
|
||||
}
|
||||
}
|
||||
|
||||
fn max_assign(&mut self, other: Self) {
|
||||
if *self < other {
|
||||
*self = other;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://drafts.csswg.org/css-tables/#border-specificity>
|
||||
/// > Given two borders styles, the border style having the most specificity is the border style which…
|
||||
/// > 1. … has the value "hidden" as border-style, if only one does
|
||||
/// > 2. … has the biggest border-width, once converted into css pixels
|
||||
/// > 3. … has the border-style which comes first in the following list:
|
||||
/// > double, solid, dashed, dotted, ridge, outset, groove, inset, none
|
||||
impl Ord for CollapsedBorder {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
let style_specificity = |border: &Self| match border.style {
|
||||
BorderStyle::None => 0,
|
||||
BorderStyle::Inset => 1,
|
||||
BorderStyle::Groove => 2,
|
||||
BorderStyle::Outset => 3,
|
||||
BorderStyle::Ridge => 4,
|
||||
BorderStyle::Dotted => 5,
|
||||
BorderStyle::Dashed => 6,
|
||||
BorderStyle::Solid => 7,
|
||||
BorderStyle::Double => 8,
|
||||
BorderStyle::Hidden => 9,
|
||||
};
|
||||
((self.style == BorderStyle::Hidden).cmp(&(other.style == BorderStyle::Hidden)))
|
||||
.then_with(|| self.width.cmp(&other.width))
|
||||
.then_with(|| style_specificity(self).cmp(&style_specificity(other)))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for CollapsedBorder {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
/// The calculated collapsed borders.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct CollapsedBorders {
|
||||
block: Vec<Au>,
|
||||
inline: Vec<Au>,
|
||||
block: Vec<CollapsedBorder>,
|
||||
inline: Vec<CollapsedBorder>,
|
||||
}
|
||||
|
||||
/// A helper struct that performs the layout of the box tree version
|
||||
|
@ -2149,10 +2220,32 @@ impl<'a> TableLayout<'a> {
|
|||
}
|
||||
|
||||
let mut collapsed_borders = CollapsedBorders {
|
||||
block: vec![Au::zero(); self.table.size.height + 1],
|
||||
inline: vec![Au::zero(); self.table.size.width + 1],
|
||||
block: vec![Default::default(); self.table.size.height + 1],
|
||||
inline: vec![Default::default(); 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);
|
||||
};
|
||||
let all_rows = 0..self.table.size.height;
|
||||
let all_columns = 0..self.table.size.width;
|
||||
for column_group in &self.table.column_groups {
|
||||
apply_border(&column_group.style, &all_rows, &column_group.track_range);
|
||||
}
|
||||
for (column_index, column) in self.table.columns.iter().enumerate() {
|
||||
apply_border(&column.style, &all_rows, &(column_index..column_index + 1));
|
||||
}
|
||||
for row_group in &self.table.row_groups {
|
||||
apply_border(&row_group.style, &row_group.track_range, &all_columns);
|
||||
}
|
||||
for (row_index, row) in self.table.rows.iter().enumerate() {
|
||||
apply_border(&row.style, &(row_index..row_index + 1), &all_columns);
|
||||
}
|
||||
for row_index in 0..self.table.size.height {
|
||||
for column_index in 0..self.table.size.width {
|
||||
let cell = match self.table.slots[row_index][column_index] {
|
||||
|
@ -2160,11 +2253,11 @@ impl<'a> TableLayout<'a> {
|
|||
_ => continue,
|
||||
};
|
||||
|
||||
let border = cell.style.border_width(writing_mode);
|
||||
collapsed_borders.block[row_index].max_assign(border.block_start);
|
||||
collapsed_borders.block[row_index + cell.rowspan].max_assign(border.block_end);
|
||||
collapsed_borders.inline[column_index].max_assign(border.inline_start);
|
||||
collapsed_borders.inline[column_index + cell.colspan].max_assign(border.inline_end);
|
||||
apply_border(
|
||||
&cell.style,
|
||||
&(row_index..row_index + cell.rowspan),
|
||||
&(column_index..column_index + cell.colspan),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2180,10 +2273,10 @@ impl<'a> TableLayout<'a> {
|
|||
let end_x = coordinates.x + cell.colspan;
|
||||
let end_y = coordinates.y + cell.rowspan;
|
||||
let mut result = LogicalSides {
|
||||
inline_start: collapsed_borders.inline[coordinates.x],
|
||||
inline_end: collapsed_borders.inline[end_x],
|
||||
block_start: collapsed_borders.block[coordinates.y],
|
||||
block_end: collapsed_borders.block[end_y],
|
||||
inline_start: collapsed_borders.inline[coordinates.x].width,
|
||||
inline_end: collapsed_borders.inline[end_x].width,
|
||||
block_start: collapsed_borders.block[coordinates.y].width,
|
||||
block_end: collapsed_borders.block[end_y].width,
|
||||
};
|
||||
|
||||
if coordinates.x != 0 {
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
[border-conflict-style-101.xht]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[border-conflict-style-102.xht]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[border-conflict-style-103.xht]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[border-conflict-style-104.xht]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[border-conflict-style-105.xht]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[border-conflict-style-106.xht]
|
||||
expected: FAIL
|
|
@ -1,3 +0,0 @@
|
|||
[border-writing-mode-dynamic-001.html]
|
||||
[Table borders track writing mode changes]
|
||||
expected: FAIL
|
|
@ -1,3 +0,0 @@
|
|||
[col_removal.html]
|
||||
[Table grid syncs after COL removal]
|
||||
expected: FAIL
|
2
tests/wpt/meta/css/css-tables/rules-groups.html.ini
vendored
Normal file
2
tests/wpt/meta/css/css-tables/rules-groups.html.ini
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
[rules-groups.html]
|
||||
expected: FAIL
|
Loading…
Add table
Add a link
Reference in a new issue