diff --git a/components/layout/construct.rs b/components/layout/construct.rs index f59afba4696..4422c8bfcdf 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -52,7 +52,7 @@ use std::collections::DList; use std::mem; use std::sync::atomic::Relaxed; use style::ComputedValues; -use style::computed_values::{display, position, float, list_style_position}; +use style::computed_values::{display, empty_cells, float, list_style_position, position}; use sync::Arc; use url::Url; @@ -157,8 +157,8 @@ struct InlineFragmentsAccumulator { /// The list of fragments. fragments: DList, - /// Whether we've created a range to enclose all the fragments. This will be Some() if the outer node - /// is an inline and None otherwise. + /// Whether we've created a range to enclose all the fragments. This will be Some() if the + /// outer node is an inline and None otherwise. enclosing_style: Option>, } @@ -914,7 +914,18 @@ impl<'a> FlowConstructor<'a> { /// possibly other `BlockFlow`s or `InlineFlow`s underneath it. fn build_flow_for_table_cell(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult { let fragment = Fragment::new_from_specific_info(node, SpecificFragmentInfo::TableCell); - let flow = box TableCellFlow::from_node_and_fragment(node, fragment) as Box; + + // Determine if the table cell should be hidden. Per CSS 2.1 § 17.6.1.1, this will be true + // if the cell has any in-flow elements (even empty ones!) and has `empty-cells` set to + // `hide`. + let hide = node.style().get_inheritedtable().empty_cells == empty_cells::hide && + node.children().all(|kid| { + let position = kid.style().get_box().position; + !kid.is_content() || position == position::absolute || position == position::fixed + }); + + let flow = box TableCellFlow::from_node_fragment_and_visibility_flag(node, fragment, !hide) + as Box; self.build_flow_for_block(FlowRef::new(flow), node) } diff --git a/components/layout/flow.rs b/components/layout/flow.rs index 11ec16e86e5..ebc78b6197f 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -59,7 +59,7 @@ use std::iter::Zip; use std::raw; use std::sync::atomic::{AtomicUint, SeqCst}; use std::slice::MutItems; -use style::computed_values::{clear, float, position, text_align}; +use style::computed_values::{clear, empty_cells, float, position, text_align}; use style::ComputedValues; use sync::Arc; @@ -1067,12 +1067,18 @@ impl<'a> ImmutableFlowUtils for &'a Flow + 'a { fn generate_missing_child_flow(self, node: &ThreadSafeLayoutNode) -> FlowRef { let flow = match self.class() { FlowClass::Table | FlowClass::TableRowGroup => { - let fragment = Fragment::new_anonymous_table_fragment(node, SpecificFragmentInfo::TableRow); + let fragment = + Fragment::new_anonymous_table_fragment(node, + SpecificFragmentInfo::TableRow); box TableRowFlow::from_node_and_fragment(node, fragment) as Box }, FlowClass::TableRow => { - let fragment = Fragment::new_anonymous_table_fragment(node, SpecificFragmentInfo::TableCell); - box TableCellFlow::from_node_and_fragment(node, fragment) as Box + let fragment = + Fragment::new_anonymous_table_fragment(node, + SpecificFragmentInfo::TableCell); + let hide = node.style().get_inheritedtable().empty_cells == empty_cells::hide; + box TableCellFlow::from_node_fragment_and_visibility_flag(node, fragment, !hide) as + Box }, _ => { panic!("no need to generate a missing child") diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs index 45e4ab3a1c3..a10ac9cf7a2 100644 --- a/components/layout/table_cell.rs +++ b/components/layout/table_cell.rs @@ -8,7 +8,7 @@ use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag}; use context::LayoutContext; -use flow::{FlowClass, Flow}; +use flow::{Flow, FlowClass}; use fragment::{Fragment, FragmentBoundsIterator}; use model::{MaybeAuto}; use layout_debug; @@ -27,15 +27,21 @@ pub struct TableCellFlow { pub block_flow: BlockFlow, /// The column span of this cell. pub column_span: u32, + /// Whether this cell is visible. If false, the value of `empty-cells` means that we must not + /// display this cell. + pub visible: bool, } impl TableCellFlow { - pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode, fragment: Fragment) - -> TableCellFlow { + pub fn from_node_fragment_and_visibility_flag(node: &ThreadSafeLayoutNode, + fragment: Fragment, + visible: bool) + -> TableCellFlow { TableCellFlow { block_flow: BlockFlow::from_node_and_fragment(node, fragment), column_span: node.get_unsigned_integer_attribute(UnsignedIntegerAttribute::ColSpanUnsignedIntegerAttribute) .unwrap_or(1), + visible: visible, } } @@ -53,7 +59,9 @@ impl TableCellFlow { /// methods. #[inline(always)] fn assign_block_size_table_cell_base<'a>(&mut self, layout_context: &'a LayoutContext<'a>) { - self.block_flow.assign_block_size_block_base(layout_context, MarginsMayCollapseFlag::MarginsMayNotCollapse) + self.block_flow.assign_block_size_block_base( + layout_context, + MarginsMayCollapseFlag::MarginsMayNotCollapse) } } @@ -145,7 +153,9 @@ impl Flow for TableCellFlow { } fn build_display_list(&mut self, layout_context: &LayoutContext) { - self.block_flow.build_display_list(layout_context) + if self.visible { + self.block_flow.build_display_list(layout_context) + } } fn repair_style(&mut self, new_style: &Arc) { diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index e17f8ea4242..53677273832 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -1000,6 +1000,15 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { _ => panic!("no layout data for this node"), } } + + /// Returns true if this node contributes content. This is used in the implementation of + /// `empty_cells` per CSS 2.1 § 17.6.1.1. + pub fn is_content(&self) -> bool { + match self.type_id() { + Some(NodeTypeId::Element(..)) | Some(NodeTypeId::Text(..)) => true, + _ => false + } + } } pub struct ThreadSafeLayoutNodeChildrenIterator<'a> { diff --git a/components/style/properties/mod.rs.mako b/components/style/properties/mod.rs.mako index 1dd3ed561d0..0456bc66cc4 100644 --- a/components/style/properties/mod.rs.mako +++ b/components/style/properties/mod.rs.mako @@ -1326,6 +1326,10 @@ pub mod longhands { ${single_keyword("table-layout", "auto fixed")} + ${new_style_struct("InheritedTable", is_inherited=True)} + + ${single_keyword("empty-cells", "show hide")} + // CSS 2.1, Section 18 - User interface diff --git a/tests/ref/basic.list b/tests/ref/basic.list index 3976d902d9e..db32e010f43 100644 --- a/tests/ref/basic.list +++ b/tests/ref/basic.list @@ -215,3 +215,4 @@ fragment=top != ../html/acid2.html acid2_ref.html == legacy_table_border_attribute_a.html legacy_table_border_attribute_ref.html == inset.html inset_ref.html == outset.html outset_ref.html +== empty_cells_a.html empty_cells_ref.html diff --git a/tests/ref/empty_cells_a.html b/tests/ref/empty_cells_a.html new file mode 100644 index 00000000000..40396ef5c45 --- /dev/null +++ b/tests/ref/empty_cells_a.html @@ -0,0 +1,25 @@ + + + + + + + + + + + +
YoHowdy
 
LaterSee yaAloha
Sayonara
+ + + diff --git a/tests/ref/empty_cells_ref.html b/tests/ref/empty_cells_ref.html new file mode 100644 index 00000000000..94dcfaa2889 --- /dev/null +++ b/tests/ref/empty_cells_ref.html @@ -0,0 +1,19 @@ + + + + + + + + + + + +
YoHowdy
LaterSee yaAloha
Sayonara
+ + +