diff options
Diffstat (limited to 'components/layout_2020')
-rw-r--r-- | components/layout_2020/style_ext.rs | 22 | ||||
-rw-r--r-- | components/layout_2020/table/layout.rs | 121 |
2 files changed, 128 insertions, 15 deletions
diff --git a/components/layout_2020/style_ext.rs b/components/layout_2020/style_ext.rs index 53bf9e6df33..21283395789 100644 --- a/components/layout_2020/style_ext.rs +++ b/components/layout_2020/style_ext.rs @@ -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( diff --git a/components/layout_2020/table/layout.rs b/components/layout_2020/table/layout.rs index e52bab12400..ed4aef17bf4 100644 --- a/components/layout_2020/table/layout.rs +++ b/components/layout_2020/table/layout.rs @@ -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 { |