diff options
26 files changed, 228 insertions, 226 deletions
diff --git a/components/layout_2020/construct_modern.rs b/components/layout_2020/construct_modern.rs index 96fa29b9c96..07b8c6e983f 100644 --- a/components/layout_2020/construct_modern.rs +++ b/components/layout_2020/construct_modern.rs @@ -7,7 +7,6 @@ use std::borrow::Cow; use rayon::iter::{IntoParallelIterator, ParallelIterator}; -use style::values::computed::TextDecorationLine; use crate::context::LayoutContext; use crate::dom::{BoxSlot, NodeExt}; @@ -20,12 +19,13 @@ use crate::formatting_contexts::{ }; use crate::layout_box_base::LayoutBoxBase; use crate::style_ext::DisplayGeneratingBox; +use crate::PropagatedBoxTreeData; -/// <https://drafts.csswg.org/css-flexbox/#flex-items> +/// A builder used for both flex and grid containers. pub(crate) struct ModernContainerBuilder<'a, 'dom, Node> { context: &'a LayoutContext<'a>, info: &'a NodeAndStyleInfo<Node>, - text_decoration_line: TextDecorationLine, + propagated_data: PropagatedBoxTreeData, contiguous_text_runs: Vec<ModernContainerTextRun<'dom, Node>>, /// To be run in parallel with rayon in `finish` jobs: Vec<ModernContainerJob<'dom, Node>>, @@ -108,12 +108,12 @@ where pub fn new( context: &'a LayoutContext<'a>, info: &'a NodeAndStyleInfo<Node>, - text_decoration_line: TextDecorationLine, + propagated_data: PropagatedBoxTreeData, ) -> Self { ModernContainerBuilder { context, info, - text_decoration_line, + propagated_data: propagated_data.disallowing_percentage_table_columns(), contiguous_text_runs: Vec::new(), jobs: Vec::new(), has_text_runs: false, @@ -164,7 +164,7 @@ where let inline_formatting_context = inline_formatting_context_builder.finish( self.context, - self.text_decoration_line, + self.propagated_data, true, /* has_first_formatted_line */ false, /* is_single_line_text_box */ self.info.style.writing_mode.to_bidi_level(), @@ -195,17 +195,21 @@ where box_slot, } => { let is_abspos = info.style.get_box().position.is_absolutely_positioned(); + + // Text decorations are not propagated to any out-of-flow descendants. In addition, + // absolutes don't affect the size of ancestors so it is fine to allow descendent + // tables to resolve percentage columns. + let propagated_data = match is_abspos { + false => self.propagated_data, + true => PropagatedBoxTreeData::default(), + }; + let formatting_context = IndependentFormattingContext::construct( self.context, &info, display.display_inside(), contents, - // Text decorations are not propagated to any out-of-flow descendants. - if is_abspos { - TextDecorationLine::NONE - } else { - self.text_decoration_line - }, + propagated_data, ); if is_abspos { diff --git a/components/layout_2020/flexbox/mod.rs b/components/layout_2020/flexbox/mod.rs index 32c1023214f..8583d26c88b 100644 --- a/components/layout_2020/flexbox/mod.rs +++ b/components/layout_2020/flexbox/mod.rs @@ -12,7 +12,6 @@ use style::properties::longhands::flex_wrap::computed_value::T as FlexWrap; use style::properties::ComputedValues; use style::values::computed::{AlignContent, JustifyContent}; use style::values::specified::align::AlignFlags; -use style::values::specified::text::TextDecorationLine; use crate::cell::ArcRefCell; use crate::construct_modern::{ModernContainerBuilder, ModernItemKind}; @@ -22,7 +21,7 @@ use crate::dom_traversal::{NodeAndStyleInfo, NonReplacedContents}; use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout}; use crate::fragment_tree::BaseFragmentInfo; use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; -use crate::ContainingBlock; +use crate::{ContainingBlock, PropagatedBoxTreeData}; mod geom; mod layout; @@ -102,12 +101,10 @@ impl FlexContainer { context: &LayoutContext, info: &NodeAndStyleInfo<impl NodeExt<'dom>>, contents: NonReplacedContents, - propagated_text_decoration_line: TextDecorationLine, + propagated_data: PropagatedBoxTreeData, ) -> Self { - let text_decoration_line = - propagated_text_decoration_line | info.style.clone_text_decoration_line(); - - let mut builder = ModernContainerBuilder::new(context, info, text_decoration_line); + let mut builder = + ModernContainerBuilder::new(context, info, propagated_data.union(&info.style)); contents.traverse(context, info, &mut builder); let items = builder.finish(); diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs index d14d4347dfa..f458c5713dc 100644 --- a/components/layout_2020/flow/construct.rs +++ b/components/layout_2020/flow/construct.rs @@ -11,7 +11,6 @@ use style::properties::longhands::list_style_position::computed_value::T as List use style::properties::ComputedValues; use style::selector_parser::PseudoElement; use style::str::char_is_whitespace; -use style::values::specified::text::TextDecorationLine; use super::inline::construct::InlineFormattingContextBuilder; use super::inline::inline_box::InlineBox; @@ -30,13 +29,14 @@ use crate::layout_box_base::LayoutBoxBase; use crate::positioned::AbsolutelyPositionedBox; use crate::style_ext::{ComputedValuesExt, DisplayGeneratingBox, DisplayInside, DisplayOutside}; use crate::table::{AnonymousTableContent, Table}; +use crate::PropagatedBoxTreeData; impl BlockFormattingContext { pub(crate) fn construct<'dom, Node>( context: &LayoutContext, info: &NodeAndStyleInfo<Node>, contents: NonReplacedContents, - propagated_text_decoration_line: TextDecorationLine, + propagated_data: PropagatedBoxTreeData, is_list_item: bool, ) -> Self where @@ -46,7 +46,7 @@ impl BlockFormattingContext { context, info, contents, - propagated_text_decoration_line, + propagated_data, is_list_item, )) } @@ -63,6 +63,7 @@ impl BlockFormattingContext { struct BlockLevelJob<'dom, Node> { info: NodeAndStyleInfo<Node>, box_slot: BoxSlot<'dom>, + propagated_data: PropagatedBoxTreeData, kind: BlockLevelCreator, } @@ -71,7 +72,6 @@ enum BlockLevelCreator { Independent { display_inside: DisplayInside, contents: Contents, - propagated_text_decoration_line: TextDecorationLine, }, OutOfFlowAbsolutelyPositionedBox { display_inside: DisplayInside, @@ -100,7 +100,7 @@ enum IntermediateBlockContainer { InlineFormattingContext(BlockContainer), Deferred { contents: NonReplacedContents, - propagated_text_decoration_line: TextDecorationLine, + propagated_data: PropagatedBoxTreeData, is_list_item: bool, }, } @@ -135,8 +135,8 @@ pub(crate) struct BlockContainerBuilder<'dom, 'style, Node> { /// be considered the first line for the purposes of `text-indent`. have_already_seen_first_line_for_text_indent: bool, - /// The propagated [`TextDecorationLine`]. - text_decoration_line: TextDecorationLine, + /// The propagated data to use for BoxTree construction. + propagated_data: PropagatedBoxTreeData, inline_formatting_context_builder: InlineFormattingContextBuilder, @@ -155,14 +155,13 @@ impl BlockContainer { context: &LayoutContext, info: &NodeAndStyleInfo<Node>, contents: NonReplacedContents, - propagated_text_decoration_line: TextDecorationLine, + propagated_data: PropagatedBoxTreeData, is_list_item: bool, ) -> BlockContainer where Node: NodeExt<'dom>, { - let mut builder = - BlockContainerBuilder::new(context, info, propagated_text_decoration_line); + let mut builder = BlockContainerBuilder::new(context, info, propagated_data); if is_list_item { if let Some(marker_contents) = crate::lists::make_marker(context, info) { @@ -189,16 +188,13 @@ where pub(crate) fn new( context: &'style LayoutContext, info: &'style NodeAndStyleInfo<Node>, - propagated_text_decoration_line: TextDecorationLine, + propagated_data: PropagatedBoxTreeData, ) -> Self { - let text_decoration_line = - propagated_text_decoration_line | info.style.clone_text_decoration_line(); - BlockContainerBuilder { context, info, block_level_boxes: Vec::new(), - text_decoration_line, + propagated_data: propagated_data.union(&info.style), have_already_seen_first_line_for_text_indent: false, anonymous_style: None, anonymous_table_content: Vec::new(), @@ -215,7 +211,7 @@ where if let Some(inline_formatting_context) = self.inline_formatting_context_builder.finish( self.context, - self.text_decoration_line, + self.propagated_data, !self.have_already_seen_first_line_for_text_indent, self.info.is_single_line_text_input(), self.info.style.writing_mode.to_bidi_level(), @@ -266,10 +262,9 @@ where // > Note that text decorations are not propagated to floating and absolutely // > positioned descendants, nor to the contents of atomic inline-level descendants // > such as inline blocks and inline tables. - let propagated_text_decoration_line = if inline_table { - TextDecorationLine::NONE - } else { - self.text_decoration_line + let propagated_data = match inline_table { + true => self.propagated_data.without_text_decorations(), + false => self.propagated_data, }; let contents: Vec<AnonymousTableContent<'dom, Node>> = @@ -279,12 +274,7 @@ where _ => None, }; - let ifc = Table::construct_anonymous( - self.context, - self.info, - contents, - propagated_text_decoration_line, - ); + let ifc = Table::construct_anonymous(self.context, self.info, contents, propagated_data); if inline_table { self.inline_formatting_context_builder.push_atomic(ifc); @@ -296,6 +286,7 @@ where info: anonymous_info, box_slot: BoxSlot::dummy(), kind: BlockLevelCreator::AnonymousTable { table_block }, + propagated_data, }); } @@ -418,6 +409,7 @@ where info: info.clone(), box_slot: BoxSlot::dummy(), kind: BlockLevelCreator::OutsideMarker { contents }, + propagated_data: self.propagated_data.without_text_decorations(), }); } @@ -439,7 +431,7 @@ where display_inside, contents, // Text decorations are not propagated to atomic inline-level descendants. - TextDecorationLine::NONE, + self.propagated_data.without_text_decorations(), ), ); box_slot.set(LayoutBox::InlineLevel(atomic)); @@ -489,7 +481,7 @@ where .inline_formatting_context_builder .split_around_block_and_finish( self.context, - self.text_decoration_line, + self.propagated_data, !self.have_already_seen_first_line_for_text_indent, self.info.style.writing_mode.to_bidi_level(), ) @@ -497,7 +489,7 @@ where self.push_block_level_job_for_inline_formatting_context(inline_formatting_context); } - let propagated_text_decoration_line = self.text_decoration_line; + let propagated_data = self.propagated_data; let kind = match contents { Contents::NonReplaced(contents) => match display_inside { DisplayInside::Flow { is_list_item } @@ -506,7 +498,7 @@ where BlockLevelCreator::SameFormattingContextBlock( IntermediateBlockContainer::Deferred { contents, - propagated_text_decoration_line, + propagated_data, is_list_item, }, ) @@ -514,7 +506,6 @@ where _ => BlockLevelCreator::Independent { display_inside, contents: contents.into(), - propagated_text_decoration_line, }, }, Contents::Replaced(contents) => { @@ -522,7 +513,6 @@ where BlockLevelCreator::Independent { display_inside, contents, - propagated_text_decoration_line, } }, }; @@ -530,6 +520,7 @@ where info: info.clone(), box_slot, kind, + propagated_data, }); // Any block also counts as the first line for the purposes of text indent. Even if @@ -565,6 +556,7 @@ where info: info.clone(), box_slot, kind, + propagated_data: self.propagated_data.without_text_decorations(), }); } @@ -583,6 +575,7 @@ where info, display_inside, contents, + self.propagated_data, )); box_slot.set(LayoutBox::InlineLevel(inline_level_box)); return; @@ -596,13 +589,14 @@ where info: info.clone(), box_slot, kind, + propagated_data: self.propagated_data.without_text_decorations(), }); } fn end_ongoing_inline_formatting_context(&mut self) { if let Some(inline_formatting_context) = self.inline_formatting_context_builder.finish( self.context, - self.text_decoration_line, + self.propagated_data, !self.have_already_seen_first_line_for_text_indent, self.info.is_single_line_text_input(), self.info.style.writing_mode.to_bidi_level(), @@ -638,6 +632,7 @@ where BlockContainer::InlineFormattingContext(inline_formatting_context), ), ), + propagated_data: self.propagated_data, }); self.have_already_seen_first_line_for_text_indent = true; @@ -663,14 +658,13 @@ where BlockLevelCreator::Independent { display_inside, contents, - propagated_text_decoration_line, } => { let context = IndependentFormattingContext::construct( context, info, display_inside, contents, - propagated_text_decoration_line, + self.propagated_data, ); ArcRefCell::new(BlockLevelBox::Independent(context)) }, @@ -693,6 +687,7 @@ where info, display_inside, contents, + self.propagated_data, ))), BlockLevelCreator::OutsideMarker { contents } => { let marker_style = context @@ -708,7 +703,7 @@ where context, &info.new_replacing_style(marker_style.clone()), contents, - TextDecorationLine::empty(), + self.propagated_data.without_text_decorations(), false, /* is_list_item */ ); ArcRefCell::new(BlockLevelBox::OutsideMarker(OutsideMarker { @@ -737,15 +732,9 @@ impl IntermediateBlockContainer { match self { IntermediateBlockContainer::Deferred { contents, - propagated_text_decoration_line, + propagated_data, is_list_item, - } => BlockContainer::construct( - context, - info, - contents, - propagated_text_decoration_line, - is_list_item, - ), + } => BlockContainer::construct(context, info, contents, propagated_data, is_list_item), IntermediateBlockContainer::InlineFormattingContext(block_container) => block_container, } } diff --git a/components/layout_2020/flow/float.rs b/components/layout_2020/flow/float.rs index 0967ad3006a..5ebcfbb2615 100644 --- a/components/layout_2020/flow/float.rs +++ b/components/layout_2020/flow/float.rs @@ -19,7 +19,6 @@ use style::computed_values::position::T as Position; use style::logical_geometry::WritingMode; use style::properties::ComputedValues; use style::values::computed::Clear as StyleClear; -use style::values::specified::text::TextDecorationLine; use crate::context::LayoutContext; use crate::dom::NodeExt; @@ -29,7 +28,7 @@ use crate::fragment_tree::{BoxFragment, CollapsedMargin}; use crate::geom::{LogicalRect, LogicalVec2, ToLogical}; use crate::positioned::{relative_adjustement, PositioningContext}; use crate::style_ext::{DisplayInside, PaddingBorderMargin}; -use crate::ContainingBlock; +use crate::{ContainingBlock, PropagatedBoxTreeData}; /// A floating box. #[derive(Debug)] @@ -902,6 +901,7 @@ impl FloatBox { info: &NodeAndStyleInfo<impl NodeExt<'dom>>, display_inside: DisplayInside, contents: Contents, + propagated_data: PropagatedBoxTreeData, ) -> Self { Self { contents: IndependentFormattingContext::construct( @@ -910,7 +910,7 @@ impl FloatBox { display_inside, contents, // Text decorations are not propagated to any out-of-flow descendants - TextDecorationLine::NONE, + propagated_data.without_text_decorations(), ), } } diff --git a/components/layout_2020/flow/inline/construct.rs b/components/layout_2020/flow/inline/construct.rs index f87cba344ec..2e05e2f0056 100644 --- a/components/layout_2020/flow/inline/construct.rs +++ b/components/layout_2020/flow/inline/construct.rs @@ -8,7 +8,6 @@ use std::char::{ToLowercase, ToUppercase}; use icu_segmenter::WordSegmenter; use servo_arc::Arc; use style::computed_values::white_space_collapse::T as WhiteSpaceCollapse; -use style::values::computed::TextDecorationLine; use style::values::specified::text::TextTransformCase; use unicode_bidi::Level; @@ -22,6 +21,7 @@ use crate::flow::float::FloatBox; use crate::formatting_contexts::IndependentFormattingContext; use crate::positioned::AbsolutelyPositionedBox; use crate::style_ext::ComputedValuesExt; +use crate::PropagatedBoxTreeData; #[derive(Default)] pub(crate) struct InlineFormattingContextBuilder { @@ -271,7 +271,7 @@ impl InlineFormattingContextBuilder { pub(crate) fn split_around_block_and_finish( &mut self, layout_context: &LayoutContext, - text_decoration_line: TextDecorationLine, + propagated_data: PropagatedBoxTreeData, has_first_formatted_line: bool, default_bidi_level: Level, ) -> Option<InlineFormattingContext> { @@ -303,7 +303,7 @@ impl InlineFormattingContextBuilder { inline_builder_from_before_split.finish( layout_context, - text_decoration_line, + propagated_data, has_first_formatted_line, /* is_single_line_text_input = */ false, default_bidi_level, @@ -314,7 +314,7 @@ impl InlineFormattingContextBuilder { pub(crate) fn finish( &mut self, layout_context: &LayoutContext, - text_decoration_line: TextDecorationLine, + propagated_data: PropagatedBoxTreeData, has_first_formatted_line: bool, is_single_line_text_input: bool, default_bidi_level: Level, @@ -329,7 +329,7 @@ impl InlineFormattingContextBuilder { Some(InlineFormattingContext::new_with_builder( old_builder, layout_context, - text_decoration_line, + propagated_data, has_first_formatted_line, is_single_line_text_input, default_bidi_level, diff --git a/components/layout_2020/flow/inline/mod.rs b/components/layout_2020/flow/inline/mod.rs index c366a8d72c6..828d490db82 100644 --- a/components/layout_2020/flow/inline/mod.rs +++ b/components/layout_2020/flow/inline/mod.rs @@ -127,7 +127,7 @@ use crate::geom::{LogicalRect, LogicalVec2, ToLogical}; use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult}; use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin}; -use crate::{ConstraintSpace, ContainingBlock}; +use crate::{ConstraintSpace, ContainingBlock, PropagatedBoxTreeData}; // From gfxFontConstants.h in Firefox. static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20; @@ -1519,7 +1519,7 @@ impl InlineFormattingContext { pub(super) fn new_with_builder( builder: InlineFormattingContextBuilder, layout_context: &LayoutContext, - text_decoration_line: TextDecorationLine, + propagated_data: PropagatedBoxTreeData, has_first_formatted_line: bool, is_single_line_text_input: bool, starting_bidi_level: Level, @@ -1570,7 +1570,7 @@ impl InlineFormattingContext { inline_items: builder.inline_items, inline_boxes: builder.inline_boxes, font_metrics, - text_decoration_line, + text_decoration_line: propagated_data.text_decoration, has_first_formatted_line, contains_floats: builder.contains_floats, is_single_line_text_input, diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index b80b106da1e..0f51c5f626d 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -30,7 +30,7 @@ use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; use crate::replaced::ReplacedContents; use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayInside}; use crate::taffy::{TaffyItemBox, TaffyItemBoxInner}; -use crate::DefiniteContainingBlock; +use crate::{DefiniteContainingBlock, PropagatedBoxTreeData}; pub struct BoxTree { /// Contains typically exactly one block-level box, which was generated by the root element. @@ -289,6 +289,8 @@ fn construct_for_root_element<'dom>( let contents = ReplacedContents::for_element(root_element, context) .map_or_else(|| NonReplacedContents::OfElement.into(), Contents::Replaced); + + let propagated_data = PropagatedBoxTreeData::default().union(&info.style); let root_box = if box_style.position.is_absolutely_positioned() { BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(ArcRefCell::new( AbsolutelyPositionedBox::construct(context, &info, display_inside, contents), @@ -299,15 +301,15 @@ fn construct_for_root_element<'dom>( &info, display_inside, contents, + propagated_data, )) } else { - let propagated_text_decoration_line = info.style.clone_text_decoration_line(); BlockLevelBox::Independent(IndependentFormattingContext::construct( context, &info, display_inside, contents, - propagated_text_decoration_line, + propagated_data, )) }; diff --git a/components/layout_2020/formatting_contexts.rs b/components/layout_2020/formatting_contexts.rs index 91cf78950b6..1e28aa01d6c 100644 --- a/components/layout_2020/formatting_contexts.rs +++ b/components/layout_2020/formatting_contexts.rs @@ -6,7 +6,6 @@ use app_units::Au; use servo_arc::Arc; use style::properties::ComputedValues; use style::selector_parser::PseudoElement; -use style::values::specified::text::TextDecorationLine; use crate::context::LayoutContext; use crate::dom::NodeExt; @@ -24,7 +23,9 @@ use crate::sizing::{self, ComputeInlineContentSizes, InlineContentSizesResult}; use crate::style_ext::{AspectRatio, DisplayInside, LayoutStyle}; use crate::table::Table; use crate::taffy::TaffyContainer; -use crate::{ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, LogicalVec2}; +use crate::{ + ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, LogicalVec2, PropagatedBoxTreeData, +}; /// <https://drafts.csswg.org/css-display/#independent-formatting-context> #[derive(Debug)] @@ -102,7 +103,7 @@ impl IndependentFormattingContext { node_and_style_info: &NodeAndStyleInfo<Node>, display_inside: DisplayInside, contents: Contents, - propagated_text_decoration_line: TextDecorationLine, + propagated_data: PropagatedBoxTreeData, ) -> Self { let mut base_fragment_info: BaseFragmentInfo = node_and_style_info.into(); @@ -115,7 +116,7 @@ impl IndependentFormattingContext { context, node_and_style_info, non_replaced_contents, - propagated_text_decoration_line, + propagated_data, is_list_item, )) }, @@ -124,7 +125,7 @@ impl IndependentFormattingContext { context, node_and_style_info, non_replaced_contents, - propagated_text_decoration_line, + propagated_data, )) }, DisplayInside::Flex => { @@ -132,7 +133,7 @@ impl IndependentFormattingContext { context, node_and_style_info, non_replaced_contents, - propagated_text_decoration_line, + propagated_data, )) }, DisplayInside::Table => { @@ -150,7 +151,7 @@ impl IndependentFormattingContext { node_and_style_info, table_grid_style, non_replaced_contents, - propagated_text_decoration_line, + propagated_data, )) }, }; diff --git a/components/layout_2020/lib.rs b/components/layout_2020/lib.rs index 940b95309c8..a3410ddff66 100644 --- a/components/layout_2020/lib.rs +++ b/components/layout_2020/lib.rs @@ -33,6 +33,7 @@ pub use fragment_tree::FragmentTree; use geom::AuOrAuto; use style::logical_geometry::WritingMode; use style::properties::ComputedValues; +use style::values::computed::TextDecorationLine; use crate::geom::{LogicalVec2, SizeConstraint}; use crate::style_ext::AspectRatio; @@ -140,3 +141,46 @@ impl<'a> From<&'_ DefiniteContainingBlock<'a>> for ContainingBlock<'a> { } } } + +/// Data that is propagated from ancestors to descendants during [`crate::flow::BoxTree`] +/// construction. This allows data to flow in the reverse direction of the typical layout +/// propoagation, but only during `BoxTree` construction. +#[derive(Clone, Copy, Debug)] +struct PropagatedBoxTreeData { + text_decoration: TextDecorationLine, + allow_percentage_column_in_tables: bool, +} + +impl Default for PropagatedBoxTreeData { + fn default() -> Self { + Self { + text_decoration: Default::default(), + allow_percentage_column_in_tables: true, + } + } +} + +impl PropagatedBoxTreeData { + pub(crate) fn union(&self, style: &ComputedValues) -> Self { + Self { + // FIXME(#31736): This is only taking into account the line style and not the decoration + // color. This should collect information about both so that they can be rendered properly. + text_decoration: self.text_decoration | style.clone_text_decoration_line(), + allow_percentage_column_in_tables: self.allow_percentage_column_in_tables, + } + } + + pub(crate) fn without_text_decorations(&self) -> Self { + Self { + text_decoration: TextDecorationLine::NONE, + allow_percentage_column_in_tables: self.allow_percentage_column_in_tables, + } + } + + fn disallowing_percentage_table_columns(&self) -> PropagatedBoxTreeData { + Self { + text_decoration: self.text_decoration, + allow_percentage_column_in_tables: false, + } + } +} diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index 9d77c396cfc..23dcd0a25ef 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -11,7 +11,6 @@ use style::computed_values::position::T as Position; use style::logical_geometry::WritingMode; use style::properties::ComputedValues; use style::values::specified::align::{AlignFlags, AxisDirection}; -use style::values::specified::text::TextDecorationLine; use style::Zero; use crate::cell::ArcRefCell; @@ -32,7 +31,8 @@ use crate::geom::{ use crate::sizing::ContentSizes; use crate::style_ext::{ComputedValuesExt, ContentBoxSizesAndPBM, DisplayInside}; use crate::{ - ConstraintSpace, ContainingBlock, ContainingBlockSize, DefiniteContainingBlock, SizeConstraint, + ConstraintSpace, ContainingBlock, ContainingBlockSize, DefiniteContainingBlock, + PropagatedBoxTreeData, SizeConstraint, }; #[derive(Debug)] @@ -75,8 +75,10 @@ impl AbsolutelyPositionedBox { node_info, display_inside, contents, - // Text decorations are not propagated to any out-of-flow descendants. - TextDecorationLine::NONE, + // Text decorations are not propagated to any out-of-flow descendants. In addition, + // absolutes don't affect the size of ancestors so it is fine to allow descendent + // tables to resolve percentage columns. + PropagatedBoxTreeData::default(), ), } } diff --git a/components/layout_2020/table/construct.rs b/components/layout_2020/table/construct.rs index 9196675530a..92fdfdff538 100644 --- a/components/layout_2020/table/construct.rs +++ b/components/layout_2020/table/construct.rs @@ -13,7 +13,6 @@ use style::properties::style_structs::Font; use style::properties::ComputedValues; use style::selector_parser::PseudoElement; use style::str::char_is_whitespace; -use style::values::specified::TextDecorationLine; use super::{ Table, TableCaption, TableSlot, TableSlotCell, TableSlotCoordinates, TableSlotOffset, @@ -31,6 +30,7 @@ use crate::formatting_contexts::{ use crate::fragment_tree::BaseFragmentInfo; use crate::layout_box_base::LayoutBoxBase; use crate::style_ext::{DisplayGeneratingBox, DisplayLayoutInternal}; +use crate::PropagatedBoxTreeData; /// A reference to a slot and its coordinates in the table #[derive(Clone, Copy, Debug)] @@ -78,12 +78,14 @@ impl Table { info: &NodeAndStyleInfo<impl NodeExt<'dom>>, grid_style: Arc<ComputedValues>, contents: NonReplacedContents, - propagated_text_decoration_line: TextDecorationLine, + propagated_data: PropagatedBoxTreeData, ) -> Self { - let text_decoration_line = - propagated_text_decoration_line | info.style.clone_text_decoration_line(); - let mut traversal = - TableBuilderTraversal::new(context, info, grid_style, text_decoration_line); + let mut traversal = TableBuilderTraversal::new( + context, + info, + grid_style, + propagated_data.union(&info.style), + ); contents.traverse(context, info, &mut traversal); traversal.finish() } @@ -92,7 +94,7 @@ impl Table { context: &LayoutContext, parent_info: &NodeAndStyleInfo<Node>, contents: Vec<AnonymousTableContent<'dom, Node>>, - propagated_text_decoration_line: style::values::specified::TextDecorationLine, + propagated_data: PropagatedBoxTreeData, ) -> IndependentFormattingContext where Node: crate::dom::NodeExt<'dom>, @@ -111,7 +113,7 @@ impl Table { context, &anonymous_info, grid_and_wrapper_style.clone(), - propagated_text_decoration_line, + propagated_data, ); for content in contents { @@ -242,9 +244,15 @@ impl TableBuilder { style: Arc<ComputedValues>, grid_style: Arc<ComputedValues>, base_fragment_info: BaseFragmentInfo, + percentage_columns_allowed_for_inline_content_sizes: bool, ) -> Self { Self { - table: Table::new(style, grid_style, base_fragment_info), + table: Table::new( + style, + grid_style, + base_fragment_info, + percentage_columns_allowed_for_inline_content_sizes, + ), incoming_rowspans: Vec::new(), } } @@ -256,6 +264,7 @@ impl TableBuilder { testing_style.clone(), testing_style.clone(), BaseFragmentInfo::anonymous(), + true, /* percentage_columns_allowed_for_inline_content_sizes */ ) } @@ -627,9 +636,9 @@ pub(crate) struct TableBuilderTraversal<'style, 'dom, Node> { context: &'style LayoutContext<'style>, info: &'style NodeAndStyleInfo<Node>, - /// The value of the [`TextDecorationLine`] to use, either for the row group + /// The value of the [`PropagatedBoxTreeData`] to use, either for the row group /// if processing one or for the table itself if outside a row group. - current_text_decoration_line: TextDecorationLine, + current_propagated_data: PropagatedBoxTreeData, /// The [`TableBuilder`] for this [`TableBuilderTraversal`]. This is separated /// into another struct so that we can write unit tests against the builder. @@ -649,13 +658,18 @@ where context: &'style LayoutContext<'style>, info: &'style NodeAndStyleInfo<Node>, grid_style: Arc<ComputedValues>, - text_decoration_line: TextDecorationLine, + propagated_data: PropagatedBoxTreeData, ) -> Self { TableBuilderTraversal { context, info, - current_text_decoration_line: text_decoration_line, - builder: TableBuilder::new(info.style.clone(), grid_style, info.into()), + current_propagated_data: propagated_data, + builder: TableBuilder::new( + info.style.clone(), + grid_style, + info.into(), + propagated_data.allow_percentage_column_in_tables, + ), current_anonymous_row_content: Vec::new(), current_row_group_index: None, } @@ -686,7 +700,7 @@ where ); let anonymous_info = self.info.new_anonymous(anonymous_style.clone()); let mut row_builder = - TableRowBuilder::new(self, &anonymous_info, self.current_text_decoration_line); + TableRowBuilder::new(self, &anonymous_info, self.current_propagated_data); for cell_content in row_content { match cell_content { @@ -758,8 +772,8 @@ where track_range: next_row_index..next_row_index, }); - let previous_text_decoration_line = self.current_text_decoration_line; - self.current_text_decoration_line |= info.style.clone_text_decoration_line(); + let previous_propagated_data = self.current_propagated_data; + self.current_propagated_data = self.current_propagated_data.union(&info.style); let new_row_group_index = self.builder.table.row_groups.len() - 1; self.current_row_group_index = Some(new_row_group_index); @@ -772,7 +786,7 @@ where self.finish_anonymous_row_if_needed(); self.current_row_group_index = None; - self.current_text_decoration_line = previous_text_decoration_line; + self.current_propagated_data = previous_propagated_data; self.builder.incoming_rowspans.clear(); // We are doing this until we have actually set a Box for this `BoxSlot`. @@ -784,7 +798,7 @@ where let context = self.context; let mut row_builder = - TableRowBuilder::new(self, info, self.current_text_decoration_line); + TableRowBuilder::new(self, info, self.current_propagated_data); NonReplacedContents::try_from(contents).unwrap().traverse( context, info, @@ -857,7 +871,7 @@ where self.context, info, non_replaced_contents, - self.current_text_decoration_line, + self.current_propagated_data, false, /* is_list_item */ )) }, @@ -910,8 +924,8 @@ struct TableRowBuilder<'style, 'builder, 'dom, 'a, Node> { current_anonymous_cell_content: Vec<AnonymousTableContent<'dom, Node>>, - /// The [`TextDecorationLine`] to use for all children of this row. - text_decoration_line: TextDecorationLine, + /// The [`PropagatedBoxTreeData`] to use for all children of this row. + propagated_data: PropagatedBoxTreeData, } impl<'style, 'builder, 'dom, 'a, Node: 'dom> TableRowBuilder<'style, 'builder, 'dom, 'a, Node> @@ -921,17 +935,15 @@ where fn new( table_traversal: &'builder mut TableBuilderTraversal<'style, 'dom, Node>, info: &'a NodeAndStyleInfo<Node>, - propagated_text_decoration_line: TextDecorationLine, + propagated_data: PropagatedBoxTreeData, ) -> Self { table_traversal.builder.start_row(); - let text_decoration_line = - propagated_text_decoration_line | info.style.clone_text_decoration_line(); TableRowBuilder { table_traversal, info, current_anonymous_cell_content: Vec::new(), - text_decoration_line, + propagated_data: propagated_data.union(&info.style), } } @@ -957,8 +969,9 @@ where &self.info.style, ); let anonymous_info = self.info.new_anonymous(anonymous_style); - let mut builder = - BlockContainerBuilder::new(context, &anonymous_info, self.text_decoration_line); + + let propagated_data = self.propagated_data.disallowing_percentage_table_columns(); + let mut builder = BlockContainerBuilder::new(context, &anonymous_info, propagated_data); for cell_content in self.current_anonymous_cell_content.drain(..) { match cell_content { @@ -1021,13 +1034,15 @@ where (rowspan, colspan) }); + let propagated_data = + self.propagated_data.disallowing_percentage_table_columns(); let contents = match contents.try_into() { Ok(non_replaced_contents) => { BlockFormattingContext::construct( self.table_traversal.context, info, non_replaced_contents, - self.text_decoration_line, + propagated_data, false, /* is_list_item */ ) }, diff --git a/components/layout_2020/table/layout.rs b/components/layout_2020/table/layout.rs index 8a6d82c532f..062e5c118bb 100644 --- a/components/layout_2020/table/layout.rs +++ b/components/layout_2020/table/layout.rs @@ -646,12 +646,51 @@ impl<'a> TableLayout<'a> { // https://drafts.csswg.org/css-tables/#gridmax: // > The row/column-grid width maximum (GRIDMAX) width is the sum of the max-content width of // > all the columns plus cell spacing or borders. - let mut grid_min_max = self - .columns - .iter() - .fold(ContentSizes::zero(), |result, measure| { - result + measure.content_sizes - }); + // + // The specification doesn't say what to do with columns with percentages, so we follow the + // approach that LayoutNG takes here. We try to figure out the size contribution + // of the percentage columns, by working backward to find the calculated + // percentage of non-percent columns and using that to calculate the size of the + // percent columns. + let mut largest_percentage_column_max_size = Au::zero(); + let mut percent_sum = 0.; + let mut non_percent_columns_max_sum = Au::zero(); + let mut grid_min_max = ContentSizes::zero(); + for column in self.columns.iter() { + match column.percentage { + Some(percentage) if !percentage.is_zero() => { + largest_percentage_column_max_size.max_assign( + column + .content_sizes + .max_content + .scale_by(1.0 / percentage.0), + ); + percent_sum += percentage.0; + }, + _ => { + non_percent_columns_max_sum += column.content_sizes.max_content; + }, + } + + grid_min_max += column.content_sizes; + } + + grid_min_max + .max_content + .max_assign(largest_percentage_column_max_size); + + // Do not take into account percentage of columns when this table is a descendant + // of a flex, grid, or table container. These modes with percentage columns can + // cause inline width to become infinitely wide. + if !percent_sum.is_zero() && + self.table + .percentage_columns_allowed_for_inline_content_sizes + { + let total_inline_size = + non_percent_columns_max_sum.scale_by(1.0 / (1.0 - percent_sum.min(1.0))); + grid_min_max.max_content.max_assign(total_inline_size); + } + assert!( grid_min_max.min_content <= grid_min_max.max_content, "GRIDMAX should never be smaller than GRIDMIN {:?}", diff --git a/components/layout_2020/table/mod.rs b/components/layout_2020/table/mod.rs index 2c16853f2f9..dfcf2b840ea 100644 --- a/components/layout_2020/table/mod.rs +++ b/components/layout_2020/table/mod.rs @@ -130,6 +130,9 @@ pub struct Table { /// Whether or not this Table is anonymous. anonymous: bool, + + /// Whether percentage columns are taken into account during inline content sizes calculation. + percentage_columns_allowed_for_inline_content_sizes: bool, } impl Table { @@ -137,6 +140,7 @@ impl Table { style: Arc<ComputedValues>, grid_style: Arc<ComputedValues>, base_fragment_info: BaseFragmentInfo, + percentage_columns_allowed_for_inline_content_sizes: bool, ) -> Self { Self { style, @@ -150,6 +154,7 @@ impl Table { slots: Vec::new(), size: TableSize::zero(), anonymous: false, + percentage_columns_allowed_for_inline_content_sizes, } } diff --git a/components/layout_2020/taffy/mod.rs b/components/layout_2020/taffy/mod.rs index 6aed847e094..e163fdfaac8 100644 --- a/components/layout_2020/taffy/mod.rs +++ b/components/layout_2020/taffy/mod.rs @@ -8,7 +8,6 @@ use std::fmt; use app_units::Au; use servo_arc::Arc; use style::properties::ComputedValues; -use style::values::computed::TextDecorationLine; use stylo_taffy::TaffyStyloStyle; use crate::cell::ArcRefCell; @@ -19,6 +18,7 @@ use crate::dom_traversal::{NodeAndStyleInfo, NonReplacedContents}; use crate::formatting_contexts::IndependentFormattingContext; use crate::fragment_tree::Fragment; use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; +use crate::PropagatedBoxTreeData; #[derive(Debug)] pub(crate) struct TaffyContainer { @@ -31,11 +31,10 @@ impl TaffyContainer { context: &LayoutContext, info: &NodeAndStyleInfo<impl NodeExt<'dom>>, contents: NonReplacedContents, - propagated_text_decoration_line: TextDecorationLine, + propagated_data: PropagatedBoxTreeData, ) -> Self { - let text_decoration_line = - propagated_text_decoration_line | info.style.clone_text_decoration_line(); - let mut builder = ModernContainerBuilder::new(context, info, text_decoration_line); + let mut builder = + ModernContainerBuilder::new(context, info, propagated_data.union(&info.style)); contents.traverse(context, info, &mut builder); let items = builder.finish(); diff --git a/tests/wpt/meta/MANIFEST.json b/tests/wpt/meta/MANIFEST.json index 4e9c021419a..9e23b6caa8a 100644 --- a/tests/wpt/meta/MANIFEST.json +++ b/tests/wpt/meta/MANIFEST.json @@ -415973,7 +415973,7 @@ ] }, "table-as-item-percent-width-cell-001-ref.html": [ - "2f40b6c49fdcee593a160c82c381d4c14f377a38", + "b8831e20e761d79ff8ee6e2bfc2a6e1243ca5f7a", [] ], "table-item-flex-percentage-min-width-ref.html": [ diff --git a/tests/wpt/meta/css/css-tables/column-track-merging.html.ini b/tests/wpt/meta/css/css-tables/column-track-merging.html.ini index f41d3d824eb..2e8779fed5e 100644 --- a/tests/wpt/meta/css/css-tables/column-track-merging.html.ini +++ b/tests/wpt/meta/css/css-tables/column-track-merging.html.ini @@ -14,9 +14,6 @@ [main table 8] expected: FAIL - [main table 12] - expected: FAIL - [main table 9] expected: FAIL diff --git a/tests/wpt/meta/css/css-tables/percent-width-cell-dynamic.html.ini b/tests/wpt/meta/css/css-tables/percent-width-cell-dynamic.html.ini deleted file mode 100644 index 3f1e27ae000..00000000000 --- a/tests/wpt/meta/css/css-tables/percent-width-cell-dynamic.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[percent-width-cell-dynamic.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-tables/percent-width-ignored-002.tentative.html.ini b/tests/wpt/meta/css/css-tables/percent-width-ignored-002.tentative.html.ini deleted file mode 100644 index bfbe9d6a505..00000000000 --- a/tests/wpt/meta/css/css-tables/percent-width-ignored-002.tentative.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[percent-width-ignored-002.tentative.html] - [#stf 1] - expected: FAIL diff --git a/tests/wpt/meta/css/css-tables/table-model-fixup.html.ini b/tests/wpt/meta/css/css-tables/table-model-fixup.html.ini index 1320421ad7b..f922038fc0b 100644 --- a/tests/wpt/meta/css/css-tables/table-model-fixup.html.ini +++ b/tests/wpt/meta/css/css-tables/table-model-fixup.html.ini @@ -1,7 +1,4 @@ [table-model-fixup.html] - [2.1. An anonymous table-row box must be generated around each sequence of consecutive children of a table-root box which are not proper table child boxes. (1/2)] - expected: FAIL - [2.2. An anonymous table-row box must be generated around each sequence of consecutive children of a table-row-grouping box which are not table-row boxes. (1/3)] expected: FAIL diff --git a/tests/wpt/meta/css/css-tables/tentative/colgroup-col.html.ini b/tests/wpt/meta/css/css-tables/tentative/colgroup-col.html.ini index 54122c07acd..78395e655ca 100644 --- a/tests/wpt/meta/css/css-tables/tentative/colgroup-col.html.ini +++ b/tests/wpt/meta/css/css-tables/tentative/colgroup-col.html.ini @@ -4,6 +4,3 @@ [table 4] expected: FAIL - - [table 6] - expected: FAIL diff --git a/tests/wpt/meta/css/css-tables/tentative/colspan-redistribution.html.ini b/tests/wpt/meta/css/css-tables/tentative/colspan-redistribution.html.ini index 4552581db90..aeba8ca6e5c 100644 --- a/tests/wpt/meta/css/css-tables/tentative/colspan-redistribution.html.ini +++ b/tests/wpt/meta/css/css-tables/tentative/colspan-redistribution.html.ini @@ -1,42 +1,9 @@ [colspan-redistribution.html] - [table 1] - expected: FAIL - - [table 2] - expected: FAIL - - [table 3] - expected: FAIL - [table 6] expected: FAIL - [table 14] - expected: FAIL - - [table 15] - expected: FAIL - - [table 16] - expected: FAIL - - [table 17] - expected: FAIL - - [table 20] - expected: FAIL - - [table 22] - expected: FAIL - [table 26] expected: FAIL - [table 27] - expected: FAIL - - [table 28] - expected: FAIL - [table 8] expected: FAIL diff --git a/tests/wpt/meta/css/css-tables/tentative/column-widths.html.ini b/tests/wpt/meta/css/css-tables/tentative/column-widths.html.ini index 31b6cf26a22..3c01677d62c 100644 --- a/tests/wpt/meta/css/css-tables/tentative/column-widths.html.ini +++ b/tests/wpt/meta/css/css-tables/tentative/column-widths.html.ini @@ -1,28 +1,4 @@ [column-widths.html] - [table 14] - expected: FAIL - - [table 19] - expected: FAIL - - [table 21] - expected: FAIL - - [table 22] - expected: FAIL - - [table 23] - expected: FAIL - - [table 25] - expected: FAIL - - [table 26] - expected: FAIL - - [table 30] - expected: FAIL - [table 32] expected: FAIL diff --git a/tests/wpt/meta/css/css-tables/tentative/table-minmax.html.ini b/tests/wpt/meta/css/css-tables/tentative/table-minmax.html.ini index 9e69b5a5022..ee1e6c4b23c 100644 --- a/tests/wpt/meta/css/css-tables/tentative/table-minmax.html.ini +++ b/tests/wpt/meta/css/css-tables/tentative/table-minmax.html.ini @@ -1,9 +1,3 @@ [table-minmax.html] - [table 2] - expected: FAIL - - [table 1] - expected: FAIL - [table 13] expected: FAIL diff --git a/tests/wpt/meta/css/css-tables/tentative/table-width-redistribution.html.ini b/tests/wpt/meta/css/css-tables/tentative/table-width-redistribution.html.ini index bd7e925f2f5..f4f31a8b831 100644 --- a/tests/wpt/meta/css/css-tables/tentative/table-width-redistribution.html.ini +++ b/tests/wpt/meta/css/css-tables/tentative/table-width-redistribution.html.ini @@ -1,12 +1,6 @@ [table-width-redistribution.html] - [table 5] - expected: FAIL - [table 6] expected: FAIL - [table 20] - expected: FAIL - - [table 22] + [table 4] expected: FAIL diff --git a/tests/wpt/meta/css/css-tables/tentative/td-box-sizing-001.html.ini b/tests/wpt/meta/css/css-tables/tentative/td-box-sizing-001.html.ini index ab1485f9841..27f3851716a 100644 --- a/tests/wpt/meta/css/css-tables/tentative/td-box-sizing-001.html.ini +++ b/tests/wpt/meta/css/css-tables/tentative/td-box-sizing-001.html.ini @@ -1,15 +1,3 @@ [td-box-sizing-001.html] - [table 1] - expected: FAIL - - [table 2] - expected: FAIL - - [table 9] - expected: FAIL - - [table 10] - expected: FAIL - [table 11] expected: FAIL diff --git a/tests/wpt/tests/css/css-flexbox/table-as-item-percent-width-cell-001-ref.html b/tests/wpt/tests/css/css-flexbox/table-as-item-percent-width-cell-001-ref.html index 2f40b6c49fd..b8831e20e76 100644 --- a/tests/wpt/tests/css/css-flexbox/table-as-item-percent-width-cell-001-ref.html +++ b/tests/wpt/tests/css/css-flexbox/table-as-item-percent-width-cell-001-ref.html @@ -8,7 +8,7 @@ width: 200px; border: 1px solid black; } - table { width: max-content; } + table { width: min-content; } td { background-color: cyan; width: 100%; |