diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/layout/block.rs | 78 | ||||
-rw-r--r-- | components/layout/fragment.rs | 3 | ||||
-rw-r--r-- | components/layout/table.rs | 237 | ||||
-rw-r--r-- | components/layout/table_row.rs | 49 | ||||
-rw-r--r-- | components/layout/table_rowgroup.rs | 40 | ||||
-rw-r--r-- | components/layout/table_wrapper.rs | 92 | ||||
-rw-r--r-- | components/layout/wrapper.rs | 4 | ||||
-rw-r--r-- | components/net/image/base.rs | 14 | ||||
-rw-r--r-- | components/script/dom/element.rs | 10 | ||||
-rw-r--r-- | components/script/dom/htmltableelement.rs | 11 | ||||
-rw-r--r-- | components/script/dom/webidls/CSSStyleDeclaration.webidl | 2 | ||||
-rw-r--r-- | components/servo/Cargo.lock | 1 | ||||
-rw-r--r-- | components/style/Cargo.toml | 1 | ||||
-rw-r--r-- | components/style/legacy.rs | 19 | ||||
-rw-r--r-- | components/style/lib.rs | 1 | ||||
-rw-r--r-- | components/style/properties.mako.rs | 83 | ||||
-rw-r--r-- | components/style/selector_matching.rs | 22 |
17 files changed, 490 insertions, 177 deletions
diff --git a/components/layout/block.rs b/components/layout/block.rs index 77c60b25b3d..7fb63c0045d 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -44,7 +44,7 @@ use incremental::{REFLOW, REFLOW_OUT_OF_FLOW}; use layout_debug; use model::{IntrinsicISizes, MarginCollapseInfo}; use model::{MaybeAuto, CollapsibleMargins, specified, specified_or_none}; -use table::ColumnComputedInlineSize; +use table; use wrapper::ThreadSafeLayoutNode; use geom::{Point2D, Rect, Size2D}; @@ -53,13 +53,13 @@ use msg::compositor_msg::LayerId; use rustc_serialize::{Encoder, Encodable}; use std::cmp::{max, min}; use std::fmt; +use std::sync::Arc; use style::computed_values::{overflow_x, overflow_y, position, box_sizing, display, float}; use style::properties::ComputedValues; use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto}; use style::values::computed::{LengthOrPercentageOrNone}; -use std::sync::Arc; use util::geometry::{Au, MAX_AU}; -use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode}; +use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize}; use util::opts; /// Information specific to floated blocks. @@ -302,11 +302,11 @@ impl BSizeConstraintSolution { /// current calculated value of `height`. /// /// See CSS 2.1 § 10.7. -struct CandidateBSizeIterator { +pub struct CandidateBSizeIterator { block_size: MaybeAuto, max_block_size: Option<Au>, min_block_size: Au, - candidate_value: Au, + pub candidate_value: Au, status: CandidateBSizeIteratorStatus, } @@ -510,7 +510,7 @@ enum FormattingContextType { // // TODO(#1244, #2007, pcwalton): Do this for CSS transforms and opacity too, at least if they're // animating. -fn propagate_layer_flag_from_child(layers_needed_for_descendants: &mut bool, kid: &mut Flow) { +pub fn propagate_layer_flag_from_child(layers_needed_for_descendants: &mut bool, kid: &mut Flow) { if kid.is_absolute_containing_block() { let kid_base = flow::mut_base(kid); if kid_base.flags.contains(NEEDS_LAYER) { @@ -1234,7 +1234,7 @@ impl BlockFlow { layout_context: &LayoutContext, inline_start_content_edge: Au, content_inline_size: Au, - optional_column_computed_inline_sizes: Option<&[ColumnComputedInlineSize]>) { + table_info: Option<table::ChildInlineSizeInfo>) { // Keep track of whether floats could impact each child. let mut inline_start_floats_impact_child = self.base.flags.contains(IMPACTED_BY_LEFT_FLOATS); @@ -1256,9 +1256,6 @@ impl BlockFlow { let fixed_static_i_offset = self.base.fixed_static_i_offset + inline_start_content_edge; let flags = self.base.flags.clone(); - // This value is used only for table cells. - let mut inline_start_margin_edge = inline_start_content_edge; - // Remember the inline-sizes of the last left and right floats, if there were any. These // are used for estimating the inline-sizes of block formatting contexts. (We estimate that // the inline-size of any block formatting context that we see will be based on the @@ -1286,7 +1283,8 @@ impl BlockFlow { (LengthOrPercentageOrAuto::Percentage(percent), Some(container_size)) => { Some(container_size.scale_by(percent)) } - (LengthOrPercentageOrAuto::Percentage(_), None) | (LengthOrPercentageOrAuto::Auto, _) => None, + (LengthOrPercentageOrAuto::Percentage(_), None) | + (LengthOrPercentageOrAuto::Auto, _) => None, (LengthOrPercentageOrAuto::Length(length), _) => Some(length), }; @@ -1299,6 +1297,13 @@ impl BlockFlow { // FIXME (mbrubeck): Get correct mode for absolute containing block let containing_block_mode = self.base.writing_mode; + // This value is used only for table cells. + let mut inline_start_margin_edge = if table_info.is_some() { + inline_start_content_edge + } else { + Au(0) + }; + for (i, kid) in self.base.child_iter().enumerate() { { let kid_base = flow::mut_base(kid); @@ -1376,16 +1381,12 @@ impl BlockFlow { } // Handle tables. - match optional_column_computed_inline_sizes { - Some(ref column_computed_inline_sizes) => { - propagate_column_inline_sizes_to_child(kid, - i, - content_inline_size, - containing_block_mode, - *column_computed_inline_sizes, - &mut inline_start_margin_edge) - } - None => {} + if let Some(ref table_info) = table_info { + table_info.propagate_to_child(kid, + i, + content_inline_size, + containing_block_mode, + &mut inline_start_margin_edge); } // Per CSS 2.1 § 16.3.1, text alignment propagates to all children in flow. @@ -2661,38 +2662,3 @@ impl ISizeAndMarginsComputer for FloatReplaced { } } -fn propagate_column_inline_sizes_to_child( - kid: &mut Flow, - child_index: uint, - content_inline_size: Au, - writing_mode: WritingMode, - column_computed_inline_sizes: &[ColumnComputedInlineSize], - inline_start_margin_edge: &mut Au) { - // If kid is table_rowgroup or table_row, the column inline-sizes info should be copied from - // its parent. - // - // FIXME(pcwalton): This seems inefficient. Reference count it instead? - let inline_size = if kid.is_table() || kid.is_table_rowgroup() || kid.is_table_row() { - *kid.column_computed_inline_sizes() = - column_computed_inline_sizes.iter().map(|&x| x).collect(); - - // ISize of kid flow is our content inline-size. - content_inline_size - } else if kid.is_table_cell() { - column_computed_inline_sizes[child_index].size - } else { - // ISize of kid flow is our content inline-size. - content_inline_size - }; - - { - let kid_base = flow::mut_base(kid); - kid_base.position.start.i = *inline_start_margin_edge; - kid_base.block_container_inline_size = inline_size; - kid_base.block_container_writing_mode = writing_mode; - } - - if kid.is_table_cell() { - *inline_start_margin_edge = *inline_start_margin_edge + inline_size - } -} diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 3b8dff61e63..329d7849508 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -886,7 +886,8 @@ impl Fragment { SpecificFragmentInfo::InlineBlock(_) => { QuantitiesIncludedInIntrinsicInlineSizes::all() } - SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell => { + SpecificFragmentInfo::Table | + SpecificFragmentInfo::TableCell => { INTRINSIC_INLINE_SIZE_INCLUDES_PADDING | INTRINSIC_INLINE_SIZE_INCLUDES_BORDER | INTRINSIC_INLINE_SIZE_INCLUDES_SPECIFIED diff --git a/components/layout/table.rs b/components/layout/table.rs index a1fa55889ea..7917af12904 100644 --- a/components/layout/table.rs +++ b/components/layout/table.rs @@ -6,29 +6,30 @@ #![deny(unsafe_blocks)] -use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag}; +use block::{self, BlockFlow, CandidateBSizeIterator, ISizeAndMarginsComputer}; use block::{ISizeConstraintInput, ISizeConstraintSolution}; use context::LayoutContext; use floats::FloatKind; use flow::{self, Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS}; -use flow::ImmutableFlowUtils; +use flow::{ImmutableFlowUtils, MutableFlowUtils}; use fragment::{Fragment, FragmentBorderBoxIterator}; +use incremental::{REFLOW, REFLOW_OUT_OF_FLOW}; use layout_debug; -use model::{IntrinsicISizes, IntrinsicISizesContribution}; +use model::{IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto}; use table_row::CellIntrinsicInlineSize; use table_wrapper::TableLayout; use wrapper::ThreadSafeLayoutNode; use geom::{Point2D, Rect}; -use util::geometry::Au; -use util::logical_geometry::LogicalRect; use std::cmp::max; use std::fmt; +use std::sync::Arc; +use style::computed_values::{border_collapse, border_spacing, table_layout}; use style::properties::ComputedValues; use style::values::CSSFloat; -use style::values::computed::{LengthOrPercentageOrAuto}; -use style::computed_values::table_layout; -use std::sync::Arc; +use style::values::computed::LengthOrPercentageOrAuto; +use util::geometry::Au; +use util::logical_geometry::{LogicalRect, WritingMode}; /// A table flow corresponded to the table's internal table fragment under a table wrapper flow. /// The properties `position`, `float`, and `margin-*` are used on the table wrapper fragment, @@ -140,17 +141,6 @@ impl TableFlow { total_inline_sizes } - /// Assign block-size for table flow. - /// - /// TODO(#2014, pcwalton): This probably doesn't handle margin collapse right. - /// - /// inline(always) because this is only ever called by in-order or non-in-order top-level - /// methods - #[inline(always)] - fn assign_block_size_table_base<'a>(&mut self, layout_context: &'a LayoutContext<'a>) { - self.block_flow.assign_block_size_block_base(layout_context, MarginsMayCollapseFlag::MarginsMayNotCollapse); - } - /// Updates the minimum and preferred inline-size calculation for a single row. This is /// factored out into a separate function because we process children of rowgroups too. fn update_column_inline_sizes_for_row(child: &mut Flow, @@ -183,6 +173,20 @@ impl TableFlow { } } } + + /// Returns the effective spacing per cell, taking the value of `border-collapse` into account. + fn spacing(&self) -> border_spacing::T { + let style = self.block_flow.fragment.style(); + match style.get_inheritedtable().border_collapse { + border_collapse::T::separate => style.get_inheritedtable().border_spacing, + border_collapse::T::collapse => { + border_spacing::T { + horizontal: Au(0), + vertical: Au(0), + } + } + } + } } impl Flow for TableFlow { @@ -218,6 +222,8 @@ impl Flow for TableFlow { let _scope = layout_debug_scope!("table::bubble_inline_sizes {:x}", self.block_flow.base.debug_id()); + // Don't use `compute_intrinsic_inline_sizes` here because that will count padding as + // part of the table, which we don't want to do—it belongs to the table wrapper instead. let mut computation = IntrinsicISizesContribution::new(); let mut did_first_row = false; for kid in self.block_flow.base.child_iter() { @@ -256,6 +262,14 @@ impl Flow for TableFlow { } } + let spacing = self.block_flow + .fragment + .style() + .get_inheritedtable() + .border_spacing + .horizontal * (self.column_intrinsic_inline_sizes.len() as i32 + 1); + computation.surrounding_size = computation.surrounding_size + spacing; + self.block_flow.base.intrinsic_inline_sizes = computation.finish() } @@ -272,24 +286,26 @@ impl Flow for TableFlow { let mut num_unspecified_inline_sizes = 0; let mut total_column_inline_size = Au(0); for column_inline_size in self.column_intrinsic_inline_sizes.iter() { - let this_column_inline_size = column_inline_size.minimum_length; - if this_column_inline_size == Au(0) { - num_unspecified_inline_sizes += 1 + if column_inline_size.constrained { + total_column_inline_size = total_column_inline_size + + column_inline_size.minimum_length } else { - total_column_inline_size = total_column_inline_size + this_column_inline_size + num_unspecified_inline_sizes += 1 } } let inline_size_computer = InternalTable; - inline_size_computer.compute_used_inline_size(&mut self.block_flow, layout_context, containing_block_inline_size); let inline_start_content_edge = self.block_flow.fragment.border_padding.inline_start; let padding_and_borders = self.block_flow.fragment.border_padding.inline_start_end(); + let spacing_per_cell = self.spacing(); + let spacing = spacing_per_cell.horizontal * + (self.column_intrinsic_inline_sizes.len() as i32 + 1); let content_inline_size = - self.block_flow.fragment.border_box.size.inline - padding_and_borders; + self.block_flow.fragment.border_box.size.inline - padding_and_borders - spacing; match self.table_layout { TableLayout::Fixed => { @@ -305,11 +321,9 @@ impl Flow for TableFlow { }); } } else if num_unspecified_inline_sizes != 0 { - let extra_column_inline_size = - (content_inline_size - total_column_inline_size) / - num_unspecified_inline_sizes; + let extra_column_inline_size = content_inline_size - total_column_inline_size; for column_inline_size in self.column_intrinsic_inline_sizes.iter() { - if column_inline_size.minimum_length == Au(0) && + if !column_inline_size.constrained && column_inline_size.percentage == 0.0 { self.column_computed_inline_sizes.push(ColumnComputedInlineSize { size: extra_column_inline_size / num_unspecified_inline_sizes, @@ -332,16 +346,20 @@ impl Flow for TableFlow { self.block_flow.base.flags.remove(IMPACTED_BY_LEFT_FLOATS); self.block_flow.base.flags.remove(IMPACTED_BY_RIGHT_FLOATS); - self.block_flow.propagate_assigned_inline_size_to_children( - layout_context, - inline_start_content_edge, - content_inline_size, - Some(self.column_computed_inline_sizes.as_slice())); + let info = ChildInlineSizeInfo { + column_computed_inline_sizes: self.column_computed_inline_sizes.as_slice(), + spacing: spacing_per_cell, + }; + self.block_flow.propagate_assigned_inline_size_to_children(layout_context, + inline_start_content_edge, + content_inline_size, + Some(info)); } - fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) { + fn assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) { debug!("assign_block_size: assigning block_size for table"); - self.assign_block_size_table_base(ctx); + let vertical_spacing = self.spacing().vertical; + self.block_flow.assign_block_size_for_table_like_flow(layout_context, vertical_spacing) } fn compute_absolute_position(&mut self) { @@ -417,6 +435,90 @@ impl ISizeAndMarginsComputer for InternalTable { } } +/// Encapsulates functionality shared among all table-like flows: for now, tables and table +/// rowgroups. +pub trait TableLikeFlow { + /// Lays out the rows of a table. + fn assign_block_size_for_table_like_flow<'a>(&mut self, + layout_context: &'a LayoutContext<'a>, + block_direction_spacing: Au); +} + +impl TableLikeFlow for BlockFlow { + fn assign_block_size_for_table_like_flow<'a>(&mut self, + _: &'a LayoutContext<'a>, + block_direction_spacing: Au) { + if self.base.restyle_damage.contains(REFLOW) { + // Our current border-box position. + let block_start_border_padding = self.fragment.border_padding.block_start; + let mut current_block_offset = block_start_border_padding; + + // At this point, `current_block_offset` is at the content edge of our box. Now iterate + // over children. + let mut layers_needed_for_descendants = false; + for kid in self.base.child_iter() { + // Mark flows for layerization if necessary to handle painting order correctly. + block::propagate_layer_flag_from_child(&mut layers_needed_for_descendants, kid); + + // Account for spacing. + if kid.is_table_row() { + current_block_offset = current_block_offset + block_direction_spacing; + } + + // At this point, `current_block_offset` is at the border edge of the child. + flow::mut_base(kid).position.start.b = current_block_offset; + + // Move past the child's border box. Do not use the `translate_including_floats` + // function here because the child has already translated floats past its border + // box. + let kid_base = flow::mut_base(kid); + current_block_offset = current_block_offset + kid_base.position.size.block; + } + + // Collect various offsets needed by absolutely positioned descendants. + (&mut *self as &mut Flow).collect_static_block_offsets_from_children(); + + // Compute any explicitly-specified block size. + // Can't use `for` because we assign to `candidate_block_size_iterator.candidate_value`. + let mut block_size = current_block_offset - block_start_border_padding; + let mut candidate_block_size_iterator = CandidateBSizeIterator::new( + &self.fragment, + self.base.block_container_explicit_block_size); + loop { + match candidate_block_size_iterator.next() { + Some(candidate_block_size) => { + candidate_block_size_iterator.candidate_value = + match candidate_block_size { + MaybeAuto::Auto => block_size, + MaybeAuto::Specified(value) => value + } + } + None => break, + } + } + + // Adjust `current_block_offset` as necessary to account for the explicitly-specified + // block-size. + block_size = candidate_block_size_iterator.candidate_value; + let delta = block_size - (current_block_offset - block_start_border_padding); + current_block_offset = current_block_offset + delta; + + // Take border, padding, and spacing into account. + let block_end_offset = self.fragment.border_padding.block_end + + block_direction_spacing; + current_block_offset = current_block_offset + block_end_offset; + + // Now that `current_block_offset` is at the block-end of the border box, compute the + // final border box position. + self.fragment.border_box.size.block = current_block_offset; + self.fragment.border_box.start.b = Au(0); + self.base.position.size.block = current_block_offset; + } + + self.base.restyle_damage.remove(REFLOW_OUT_OF_FLOW | REFLOW); + } +} + /// Information about the intrinsic inline sizes of columns within a table. /// /// During table inline-size bubbling, we might need to store both a percentage constraint and a @@ -472,8 +574,69 @@ impl ColumnIntrinsicInlineSize { /// /// TODO(pcwalton): There will probably be some `border-collapse`-related info in here too /// eventually. -#[derive(RustcEncodable, Copy)] +#[derive(RustcEncodable, Clone, Copy)] pub struct ColumnComputedInlineSize { /// The computed size of this inline column. pub size: Au, } + +/// Inline-size information that we need to push down to table children. +pub struct ChildInlineSizeInfo<'a> { + /// The spacing of the table. + pub spacing: border_spacing::T, + /// The computed inline sizes for each column. + pub column_computed_inline_sizes: &'a [ColumnComputedInlineSize], +} + +impl<'a> ChildInlineSizeInfo<'a> { + /// Propagates information computed during inline size assignment to a child of a table, and + /// lays out that child in the inline direction. + pub fn propagate_to_child(&self, + kid: &mut Flow, + child_index: uint, + content_inline_size: Au, + writing_mode: WritingMode, + inline_start_margin_edge: &mut Au) { + // If the child is a table or a row, copy computed inline size information from its parent. + // + // FIXME(pcwalton): This seems inefficient. Reference count it instead? + let inline_size; + if kid.is_table() { + let table_kid = kid.as_table(); + table_kid.column_computed_inline_sizes = self.column_computed_inline_sizes.to_vec(); + inline_size = content_inline_size + } else if kid.is_table_rowgroup() { + let table_rowgroup_kid = kid.as_table_rowgroup(); + table_rowgroup_kid.column_computed_inline_sizes = + self.column_computed_inline_sizes.to_vec(); + table_rowgroup_kid.spacing = self.spacing; + inline_size = content_inline_size + } else if kid.is_table_row() { + let table_row_kid = kid.as_table_row(); + table_row_kid.column_computed_inline_sizes = + self.column_computed_inline_sizes.to_vec(); + table_row_kid.spacing = self.spacing; + inline_size = content_inline_size + } else if kid.is_table_cell() { + // Take spacing into account. + *inline_start_margin_edge = *inline_start_margin_edge + self.spacing.horizontal; + inline_size = self.column_computed_inline_sizes[child_index].size; + } else { + // ISize of kid flow is our content inline-size. + inline_size = content_inline_size + } + + { + let kid_base = flow::mut_base(kid); + kid_base.position.start.i = *inline_start_margin_edge; + kid_base.block_container_inline_size = inline_size; + kid_base.block_container_writing_mode = writing_mode + } + + // Move over for the next table cell. + if kid.is_table_cell() { + *inline_start_margin_edge = *inline_start_margin_edge + inline_size + } + } +} + diff --git a/components/layout/table_row.rs b/components/layout/table_row.rs index 1e45ba48fc1..78b5a68e80a 100644 --- a/components/layout/table_row.rs +++ b/components/layout/table_row.rs @@ -12,7 +12,8 @@ use context::LayoutContext; use flow::{self, FlowClass, Flow, ImmutableFlowUtils}; use fragment::{Fragment, FragmentBorderBoxIterator}; use layout_debug; -use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable}; +use table::{ChildInlineSizeInfo, ColumnComputedInlineSize, ColumnIntrinsicInlineSize}; +use table::{InternalTable}; use model::MaybeAuto; use wrapper::ThreadSafeLayoutNode; @@ -21,9 +22,10 @@ use util::geometry::Au; use util::logical_geometry::LogicalRect; use std::cmp::max; use std::fmt; +use std::sync::Arc; +use style::computed_values::border_spacing; use style::properties::ComputedValues; use style::values::computed::LengthOrPercentageOrAuto; -use std::sync::Arc; /// A single row of a table. #[derive(RustcEncodable)] @@ -35,6 +37,10 @@ pub struct TableRowFlow { /// Information about the computed inline-sizes of each column. pub column_computed_inline_sizes: Vec<ColumnComputedInlineSize>, + + /// The spacing for this row, propagated down from the table during the inline-size assignment + /// phase. + pub spacing: border_spacing::T, } /// Information about the column inline size and span for each cell. @@ -53,6 +59,10 @@ impl TableRowFlow { block_flow: BlockFlow::from_node_and_fragment(node, fragment), cell_intrinsic_inline_sizes: Vec::new(), column_computed_inline_sizes: Vec::new(), + spacing: border_spacing::T { + horizontal: Au(0), + vertical: Au(0), + }, } } @@ -76,11 +86,9 @@ impl TableRowFlow { fn assign_block_size_table_row_base<'a>(&mut self, layout_context: &'a LayoutContext<'a>) { let (block_start_offset, _, _) = self.initialize_offsets(); - let /* mut */ cur_y = block_start_offset; - // Per CSS 2.1 § 17.5.3, find max_y = max(computed `block-size`, minimum block-size of all // cells). - let mut max_y = Au(0); + let mut max_block_size = Au(0); let thread_id = self.block_flow.base.thread_id; for kid in self.block_flow.base.child_iter() { kid.place_float_if_applicable(layout_context); @@ -93,17 +101,18 @@ impl TableRowFlow { // TODO: Percentage block-size let child_specified_block_size = MaybeAuto::from_style(child_fragment.style().content_block_size(), - Au::new(0)).specified_or_zero(); - max_y = max(max_y, - child_specified_block_size + - child_fragment.border_padding.block_start_end()); + Au(0)).specified_or_zero(); + max_block_size = + max(max_block_size, + child_specified_block_size + + child_fragment.border_padding.block_start_end()); } let child_node = flow::mut_base(kid); - child_node.position.start.b = cur_y; - max_y = max(max_y, child_node.position.size.block); + child_node.position.start.b = block_start_offset; + max_block_size = max(max_block_size, child_node.position.size.block); } - let mut block_size = max_y; + let mut block_size = max_block_size; // TODO: Percentage block-size block_size = match MaybeAuto::from_style(self.block_flow .fragment @@ -113,11 +122,8 @@ impl TableRowFlow { MaybeAuto::Auto => block_size, MaybeAuto::Specified(value) => max(value, block_size) }; - // cur_y = cur_y + block-size; // Assign the block-size of own fragment - // - // FIXME(pcwalton): Take `cur_y` into account. let mut position = self.block_flow.fragment.border_box; position.size.block = block_size; self.block_flow.fragment.border_box = position; @@ -273,11 +279,14 @@ impl Flow for TableRowFlow { } // Push those inline sizes down to the cells. - self.block_flow.propagate_assigned_inline_size_to_children( - layout_context, - inline_start_content_edge, - containing_block_inline_size, - Some(computed_inline_size_for_cells.as_slice())); + let info = ChildInlineSizeInfo { + column_computed_inline_sizes: computed_inline_size_for_cells.as_slice(), + spacing: self.spacing, + }; + self.block_flow.propagate_assigned_inline_size_to_children(layout_context, + inline_start_content_edge, + containing_block_inline_size, + Some(info)); } fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) { diff --git a/components/layout/table_rowgroup.rs b/components/layout/table_rowgroup.rs index 6ea1c4aaa18..a1d1bdc133d 100644 --- a/components/layout/table_rowgroup.rs +++ b/components/layout/table_rowgroup.rs @@ -6,12 +6,14 @@ #![deny(unsafe_blocks)] -use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag}; +use block::{BlockFlow, ISizeAndMarginsComputer}; use context::LayoutContext; use flow::{FlowClass, Flow}; use fragment::{Fragment, FragmentBorderBoxIterator}; use layout_debug; -use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable}; +use style::computed_values::border_spacing; +use table::{ChildInlineSizeInfo, ColumnComputedInlineSize, ColumnIntrinsicInlineSize}; +use table::{InternalTable, TableLikeFlow}; use wrapper::ThreadSafeLayoutNode; use geom::{Point2D, Rect}; @@ -32,6 +34,9 @@ pub struct TableRowGroupFlow { /// Information about the actual inline sizes of each column. pub column_computed_inline_sizes: Vec<ColumnComputedInlineSize>, + + /// The spacing for this rowgroup. + pub spacing: border_spacing::T, } impl TableRowGroupFlow { @@ -41,21 +46,16 @@ impl TableRowGroupFlow { block_flow: BlockFlow::from_node_and_fragment(node, fragment), column_intrinsic_inline_sizes: Vec::new(), column_computed_inline_sizes: Vec::new(), + spacing: border_spacing::T { + horizontal: Au(0), + vertical: Au(0), + }, } } pub fn fragment<'a>(&'a mut self) -> &'a Fragment { &self.block_flow.fragment } - - /// Assign block-size for table-rowgroup flow. - /// - /// inline(always) because this is only ever called by in-order or non-in-order top-level - /// methods. - #[inline(always)] - fn assign_block_size_table_rowgroup_base<'a>(&mut self, layout_context: &'a LayoutContext<'a>) { - self.block_flow.assign_block_size_block_base(layout_context, MarginsMayCollapseFlag::MarginsMayNotCollapse) - } } impl Flow for TableRowGroupFlow { @@ -109,16 +109,20 @@ impl Flow for TableRowGroupFlow { layout_context, containing_block_inline_size); - self.block_flow.propagate_assigned_inline_size_to_children( - layout_context, - inline_start_content_edge, - content_inline_size, - Some(self.column_computed_inline_sizes.as_slice())); + let info = ChildInlineSizeInfo { + column_computed_inline_sizes: self.column_computed_inline_sizes.as_slice(), + spacing: self.spacing, + }; + self.block_flow.propagate_assigned_inline_size_to_children(layout_context, + inline_start_content_edge, + content_inline_size, + Some(info)); } - fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) { + fn assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) { debug!("assign_block_size: assigning block_size for table_rowgroup"); - self.assign_block_size_table_rowgroup_base(ctx); + self.block_flow.assign_block_size_for_table_like_flow(layout_context, + self.spacing.vertical) } fn compute_absolute_position(&mut self) { diff --git a/components/layout/table_wrapper.rs b/components/layout/table_wrapper.rs index 042c08b5ed3..d37e377f92d 100644 --- a/components/layout/table_wrapper.rs +++ b/components/layout/table_wrapper.rs @@ -20,7 +20,7 @@ use floats::FloatKind; use flow::{FlowClass, Flow, ImmutableFlowUtils}; use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS}; use fragment::{Fragment, FragmentBorderBoxIterator}; -use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize}; +use table::{ChildInlineSizeInfo, ColumnComputedInlineSize, ColumnIntrinsicInlineSize}; use wrapper::ThreadSafeLayoutNode; use geom::{Point2D, Rect}; @@ -28,11 +28,11 @@ use util::geometry::Au; use std::cmp::{max, min}; use std::fmt; use std::ops::Add; -use style::properties::ComputedValues; +use std::sync::Arc; use style::computed_values::table_layout; +use style::properties::ComputedValues; use style::values::CSSFloat; use style::values::computed::LengthOrPercentageOrAuto; -use std::sync::Arc; #[derive(Copy, RustcEncodable, Debug)] pub enum TableLayout { @@ -98,11 +98,19 @@ impl TableWrapperFlow { // when normally the child computes it itself. But it has to be this way because the // padding will affect where we place the child. This is an odd artifact of the way that // tables are separated into table flows and table wrapper flows. - let available_inline_size = self.block_flow.fragment.border_box.size.inline; - let mut table_border_padding = Au(0); + let mut available_inline_size = self.block_flow.fragment.border_box.size.inline; + let (mut table_border_padding, mut spacing) = (Au(0), Au(0)); for kid in self.block_flow.base.child_iter() { if kid.is_table() { let kid_block = kid.as_block(); + let spacing_per_cell = kid_block.fragment + .style() + .get_inheritedtable() + .border_spacing + .horizontal; + spacing = spacing_per_cell * (self.column_intrinsic_inline_sizes.len() as i32 + 1); + available_inline_size = self.block_flow.fragment.border_box.size.inline; + kid_block.fragment.compute_border_and_padding(available_inline_size); kid_block.fragment.compute_block_direction_margins(available_inline_size); kid_block.fragment.compute_inline_direction_margins(available_inline_size); @@ -114,18 +122,21 @@ impl TableWrapperFlow { // FIXME(pcwalton, spec): INTRINSIC § 8 does not properly define how to compute this, but // says "the basic idea is the same as the shrink-to-fit width that CSS2.1 defines". So we // just use the shrink-to-fit inline size. - let available_inline_size = match self.block_flow.fragment.style().content_inline_size() { - LengthOrPercentageOrAuto::Auto => self.block_flow - .get_shrink_to_fit_inline_size(available_inline_size), - // FIXME(mttr) This fixes #4421 without breaking our current reftests, but I'm - // not completely sure this is "correct". - // - // That said, `available_inline_size` is, as far as I can tell, equal to the table's - // computed width property (W) and is used from this point forward in a way that seems - // to correspond with CSS 2.1 § 17.5.2.2 under "Column and caption widths - // influence the final table width as follows: ..." - _ => available_inline_size, - }; + let mut available_inline_size = + match self.block_flow.fragment.style().content_inline_size() { + LengthOrPercentageOrAuto::Auto => { + self.block_flow.get_shrink_to_fit_inline_size(available_inline_size) + } + // FIXME(mttr): This fixes #4421 without breaking our current reftests, but I'm + // not completely sure this is "correct". + // + // That said, `available_inline_size` is, as far as I can tell, equal to the + // table's computed width property (W) and is used from this point forward in a way + // that seems to correspond with CSS 2.1 § 17.5.2.2 under "Column and caption + // widths influence the final table width as follows: …" + _ => available_inline_size, + }; + available_inline_size = available_inline_size - spacing; // Compute all the guesses for the column sizes, and sum them. let mut total_guess = AutoLayoutCandidateGuess::new(); @@ -153,8 +164,8 @@ impl TableWrapperFlow { // // FIXME(pcwalton, spec): How do I deal with fractional excess? let excess_inline_size = available_inline_size - total_used_inline_size; - if excess_inline_size > Au(0) && - selection == SelectedAutoLayoutCandidateGuess::UsePreferredGuessAndDistributeExcessInlineSize { + if excess_inline_size > Au(0) && selection == + SelectedAutoLayoutCandidateGuess::UsePreferredGuessAndDistributeExcessInlineSize { let mut info = ExcessInlineSizeDistributionInfo::new(); for column_intrinsic_inline_size in self.column_intrinsic_inline_sizes.iter() { info.update(column_intrinsic_inline_size) @@ -173,10 +184,12 @@ impl TableWrapperFlow { total_used_inline_size = available_inline_size } + + self.block_flow.fragment.border_box.size.inline = total_used_inline_size + - table_border_padding; + table_border_padding + spacing; self.block_flow.base.position.size.inline = total_used_inline_size + - table_border_padding + self.block_flow.fragment.margin.inline_start_end(); + table_border_padding + spacing + self.block_flow.fragment.margin.inline_start_end(); } fn compute_used_inline_size(&mut self, @@ -301,11 +314,15 @@ impl Flow for TableWrapperFlow { None) } Some(ref assigned_column_inline_sizes) => { - self.block_flow.propagate_assigned_inline_size_to_children( - layout_context, - inline_start_content_edge, - content_inline_size, - Some(assigned_column_inline_sizes.as_slice())); + let info = ChildInlineSizeInfo { + column_computed_inline_sizes: assigned_column_inline_sizes.as_slice(), + spacing: self.block_flow.fragment.style().get_inheritedtable().border_spacing, + }; + self.block_flow + .propagate_assigned_inline_size_to_children(layout_context, + inline_start_content_edge, + content_inline_size, + Some(info)); } } @@ -458,13 +475,16 @@ impl AutoLayoutCandidateGuess { fn calculate(&self, selection: SelectedAutoLayoutCandidateGuess) -> Au { match selection { SelectedAutoLayoutCandidateGuess::UseMinimumGuess => self.minimum_guess, - SelectedAutoLayoutCandidateGuess::InterpolateBetweenMinimumGuessAndMinimumPercentageGuess(weight) => { + SelectedAutoLayoutCandidateGuess:: + InterpolateBetweenMinimumGuessAndMinimumPercentageGuess(weight) => { interp(self.minimum_guess, self.minimum_percentage_guess, weight) } - SelectedAutoLayoutCandidateGuess::InterpolateBetweenMinimumPercentageGuessAndMinimumSpecifiedGuess(weight) => { + SelectedAutoLayoutCandidateGuess:: + InterpolateBetweenMinimumPercentageGuessAndMinimumSpecifiedGuess(weight) => { interp(self.minimum_percentage_guess, self.minimum_specified_guess, weight) } - SelectedAutoLayoutCandidateGuess::InterpolateBetweenMinimumSpecifiedGuessAndPreferredGuess(weight) => { + SelectedAutoLayoutCandidateGuess:: + InterpolateBetweenMinimumSpecifiedGuessAndPreferredGuess(weight) => { interp(self.minimum_specified_guess, self.preferred_guess, weight) } SelectedAutoLayoutCandidateGuess::UsePreferredGuessAndDistributeExcessInlineSize => { @@ -590,9 +610,17 @@ impl ExcessInlineSizeDistributionInfo { total_distributed_excess_size: &mut Au) { let proportion = if self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage > Au(0) { - column_intrinsic_inline_size.preferred.to_subpx() / - self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage - .to_subpx() + // FIXME(spec, pcwalton): Gecko and WebKit do *something* here when there are + // nonconstrained columns with no percentage *and* no preferred width. What do they + // do? + if !column_intrinsic_inline_size.constrained && + column_intrinsic_inline_size.percentage == 0.0 { + column_intrinsic_inline_size.preferred.to_subpx() / + self.preferred_inline_size_of_nonconstrained_columns_with_no_percentage + .to_subpx() + } else { + 0.0 + } } else if self.count_of_nonconstrained_columns_with_no_percentage > 0 { 1.0 / (self.count_of_nonconstrained_columns_with_no_percentage as CSSFloat) } else if self.preferred_inline_size_of_constrained_columns_with_no_percentage > diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index bc89f74ea1b..52623f75ad9 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -635,8 +635,8 @@ impl<'le> TElement<'le> for LayoutElement<'le> { #[inline] fn has_nonzero_border(self) -> bool { unsafe { - match self.element - .get_unsigned_integer_attribute_for_layout(UnsignedIntegerAttribute::Border) { + match self.element.get_unsigned_integer_attribute_for_layout( + UnsignedIntegerAttribute::Border) { None | Some(0) => false, _ => true, } diff --git a/components/net/image/base.rs b/components/net/image/base.rs index 4acbd35cb75..46436ef8406 100644 --- a/components/net/image/base.rs +++ b/components/net/image/base.rs @@ -59,7 +59,12 @@ pub fn load_from_memory(buffer: &[u8]) -> Option<Image> { match stb_image::load_from_memory_with_depth(buffer, FORCE_DEPTH, true) { stb_image::LoadResult::ImageU8(mut image) => { assert!(image.depth == 4); - byte_swap(image.data.as_mut_slice()); + // handle gif separately because the alpha-channel has to be premultiplied + if is_gif(buffer) { + byte_swap_and_premultiply(image.data.as_mut_slice()); + } else { + byte_swap(image.data.as_mut_slice()); + } Some(png::Image { width: image.width as u32, height: image.height as u32, @@ -77,3 +82,10 @@ pub fn load_from_memory(buffer: &[u8]) -> Option<Image> { } } } + +fn is_gif(buffer: &[u8]) -> bool { + match buffer { + [b'G',b'I',b'F',b'8', n, b'a', ..] if n == b'7' || n == b'9' => true, + _ => false + } +} diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 4aad2fe59ff..3576f20f78c 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -317,6 +317,16 @@ impl RawLayoutElementHelpers for Element { None } } + UnsignedIntegerAttribute::CellSpacing => { + if self.is_htmltableelement() { + let this: &HTMLTableElement = mem::transmute(self); + this.get_cellspacing() + } else { + // Don't panic since `display` can cause this to be called on arbitrary + // elements. + None + } + } UnsignedIntegerAttribute::ColSpan => { if self.is_htmltablecellelement() { let this: &HTMLTableCellElement = mem::transmute(self); diff --git a/components/script/dom/htmltableelement.rs b/components/script/dom/htmltableelement.rs index e1494f67007..d7d85eb19bc 100644 --- a/components/script/dom/htmltableelement.rs +++ b/components/script/dom/htmltableelement.rs @@ -26,6 +26,7 @@ pub struct HTMLTableElement { htmlelement: HTMLElement, background_color: Cell<Option<RGBA>>, border: Cell<Option<u32>>, + cellspacing: Cell<Option<u32>>, width: Cell<LengthOrPercentageOrAuto>, } @@ -45,6 +46,7 @@ impl HTMLTableElement { document), background_color: Cell::new(None), border: Cell::new(None), + cellspacing: Cell::new(None), width: Cell::new(LengthOrPercentageOrAuto::Auto), } } @@ -94,6 +96,7 @@ impl<'a> HTMLTableElementMethods for JSRef<'a, HTMLTableElement> { pub trait HTMLTableElementHelpers { fn get_background_color(&self) -> Option<RGBA>; fn get_border(&self) -> Option<u32>; + fn get_cellspacing(&self) -> Option<u32>; fn get_width(&self) -> LengthOrPercentageOrAuto; } @@ -106,6 +109,10 @@ impl HTMLTableElementHelpers for HTMLTableElement { self.border.get() } + fn get_cellspacing(&self) -> Option<u32> { + self.cellspacing.get() + } + fn get_width(&self) -> LengthOrPercentageOrAuto { self.width.get() } @@ -132,6 +139,9 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLTableElement> { .as_slice() .chars()).unwrap_or(1))) } + &atom!("cellspacing") => { + self.cellspacing.set(str::parse_unsigned_integer(attr.value().as_slice().chars())) + } &atom!("width") => self.width.set(str::parse_length(attr.value().as_slice())), _ => () } @@ -145,6 +155,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLTableElement> { match attr.local_name() { &atom!("bgcolor") => self.background_color.set(None), &atom!("border") => self.border.set(None), + &atom!("cellspacing") => self.cellspacing.set(None), &atom!("width") => self.width.set(LengthOrPercentageOrAuto::Auto), _ => () } diff --git a/components/script/dom/webidls/CSSStyleDeclaration.webidl b/components/script/dom/webidls/CSSStyleDeclaration.webidl index bde48aaaff3..be5afa7244d 100644 --- a/components/script/dom/webidls/CSSStyleDeclaration.webidl +++ b/components/script/dom/webidls/CSSStyleDeclaration.webidl @@ -41,8 +41,10 @@ partial interface CSSStyleDeclaration { [TreatNullAs=EmptyString] attribute DOMString backgroundSize; [TreatNullAs=EmptyString] attribute DOMString border; + [TreatNullAs=EmptyString] attribute DOMString borderCollapse; [TreatNullAs=EmptyString] attribute DOMString borderColor; [TreatNullAs=EmptyString] attribute DOMString borderRadius; + [TreatNullAs=EmptyString] attribute DOMString borderSpacing; [TreatNullAs=EmptyString] attribute DOMString borderStyle; [TreatNullAs=EmptyString] attribute DOMString borderWidth; [TreatNullAs=EmptyString] attribute DOMString borderBottom; diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 5363ee2a931..41ab61464dc 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -818,6 +818,7 @@ dependencies = [ "matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mod_path 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "plugins 0.0.1", + "rustc-serialize 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", "selectors 0.1.0 (git+https://github.com/servo/rust-selectors)", "string_cache 0.0.0 (git+https://github.com/servo/string-cache)", "string_cache_macros 0.0.0 (git+https://github.com/servo/string-cache)", diff --git a/components/style/Cargo.toml b/components/style/Cargo.toml index 749d81645c8..a992d5406e9 100644 --- a/components/style/Cargo.toml +++ b/components/style/Cargo.toml @@ -36,6 +36,7 @@ git = "https://github.com/servo/string-cache" [dependencies] text_writer = "0.1.1" encoding = "0.2" +rustc-serialize = "0.2" matches = "0.1" url = "0.2.16" mod_path = "0.1" diff --git a/components/style/legacy.rs b/components/style/legacy.rs index d1451ae6bc4..65d05514754 100644 --- a/components/style/legacy.rs +++ b/components/style/legacy.rs @@ -14,7 +14,7 @@ use values::specified::CSSColor; use values::{CSSFloat, specified}; use properties::DeclaredValue::SpecifiedValue; use properties::PropertyDeclaration; -use properties::longhands; +use properties::longhands::{self, border_spacing}; use selector_matching::Stylist; use cssparser::Color; @@ -43,6 +43,8 @@ pub enum IntegerAttribute { pub enum UnsignedIntegerAttribute { /// `<td border>` Border, + /// `<table cellspacing>` + CellSpacing, /// `<td colspan>` ColSpan, } @@ -143,6 +145,21 @@ impl PresentationalHintSynthesis for Stylist { element, matching_rules_list, shareable); + match element.get_unsigned_integer_attribute( + UnsignedIntegerAttribute::CellSpacing) { + None => {} + Some(length) => { + let width_value = specified::Length::Absolute(Au::from_px(length as int)); + matching_rules_list.vec_push(from_declaration( + PropertyDeclaration::BorderSpacing( + SpecifiedValue( + border_spacing::SpecifiedValue { + horizontal: width_value, + vertical: width_value, + })))); + *shareable = false + } + } } name if *name == atom!("body") || *name == atom!("tr") || *name == atom!("thead") || *name == atom!("tbody") || *name == atom!("tfoot") => { diff --git a/components/style/lib.rs b/components/style/lib.rs index 88fa9ea2701..4e301cfc181 100644 --- a/components/style/lib.rs +++ b/components/style/lib.rs @@ -28,6 +28,7 @@ extern crate cssparser; extern crate matches; extern crate encoding; +extern crate "rustc-serialize" as rustc_serialize; extern crate string_cache; extern crate selectors; diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs index 7d3b58916e6..9592107cb81 100644 --- a/components/style/properties.mako.rs +++ b/components/style/properties.mako.rs @@ -2020,6 +2020,89 @@ pub mod longhands { ${single_keyword("caption-side", "top bottom")} + ${single_keyword("border-collapse", "separate collapse", experimental=True)} + + <%self:longhand name="border-spacing"> + use values::computed::{Context, ToComputedValue}; + + use cssparser::ToCss; + use text_writer::{self, TextWriter}; + use util::geometry::Au; + + pub mod computed_value { + use util::geometry::Au; + + #[derive(Clone, Copy, Debug, PartialEq, RustcEncodable)] + pub struct T { + pub horizontal: Au, + pub vertical: Au, + } + } + + #[derive(Clone, Debug, PartialEq)] + pub struct SpecifiedValue { + pub horizontal: specified::Length, + pub vertical: specified::Length, + } + + #[inline] + pub fn get_initial_value() -> computed_value::T { + computed_value::T { + horizontal: Au(0), + vertical: Au(0), + } + } + + impl ToCss for SpecifiedValue { + fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter { + try!(self.horizontal.to_css(dest)); + try!(dest.write_str(" ")); + self.vertical.to_css(dest) + } + } + + impl ToComputedValue for SpecifiedValue { + type ComputedValue = computed_value::T; + + #[inline] + fn to_computed_value(&self, context: &Context) -> computed_value::T { + computed_value::T { + horizontal: self.horizontal.to_computed_value(context), + vertical: self.vertical.to_computed_value(context), + } + } + } + + pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> { + let mut lengths = [ None, None ]; + for i in range(0, 2) { + match specified::Length::parse_non_negative(input) { + Err(()) => break, + Ok(length) => lengths[i] = Some(length), + } + } + if input.next().is_ok() { + return Err(()) + } + match (lengths[0], lengths[1]) { + (None, None) => Err(()), + (Some(length), None) => { + Ok(SpecifiedValue { + horizontal: length, + vertical: length, + }) + } + (Some(horizontal), Some(vertical)) => { + Ok(SpecifiedValue { + horizontal: horizontal, + vertical: vertical, + }) + } + (None, Some(_)) => panic!("shouldn't happen"), + } + } + </%self:longhand> + // CSS 2.1, Section 18 - User interface diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs index 3bd03be1eae..b0553bf31c1 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -193,16 +193,19 @@ impl Stylist { let mut shareable = true; - // Step 1: Virtual rules that are synthesized from legacy HTML attributes. - self.synthesize_presentational_hints_for_legacy_attributes(element, - applicable_declarations, - &mut shareable); - // Step 2: Normal rules. + // Step 1: Normal user-agent rules. map.user_agent.normal.get_all_matching_rules(element, parent_bf, applicable_declarations, &mut shareable); + + // Step 2: Presentational hints. + self.synthesize_presentational_hints_for_legacy_attributes(element, + applicable_declarations, + &mut shareable); + + // Step 3: User and author normal rules. map.user.normal.get_all_matching_rules(element, parent_bf, applicable_declarations, @@ -212,27 +215,27 @@ impl Stylist { applicable_declarations, &mut shareable); - // Step 3: Normal style attributes. + // Step 4: Normal style attributes. style_attribute.map(|sa| { shareable = false; applicable_declarations.vec_push( GenericDeclarationBlock::from_declarations(sa.normal.clone())) }); - // Step 4: Author-supplied `!important` rules. + // Step 5: Author-supplied `!important` rules. map.author.important.get_all_matching_rules(element, parent_bf, applicable_declarations, &mut shareable); - // Step 5: `!important` style attributes. + // Step 6: `!important` style attributes. style_attribute.map(|sa| { shareable = false; applicable_declarations.vec_push( GenericDeclarationBlock::from_declarations(sa.important.clone())) }); - // Step 6: User and UA `!important` rules. + // Step 7: User and UA `!important` rules. map.user.important.get_all_matching_rules(element, parent_bf, applicable_declarations, @@ -277,3 +280,4 @@ impl PerPseudoElementSelectorMap { } } } + |