From c264993da8a747cb3d56cf589af7fd3f9e876783 Mon Sep 17 00:00:00 2001 From: Oriol Brufau Date: Thu, 10 Aug 2023 13:38:44 +0200 Subject: [PATCH] Resolve cyclic margin and padding percentages against zero (#30085) From https://drafts.csswg.org/css-sizing-3/#min-percentage-contribution > For the min size properties, as well as for margins and paddings > (and gutters), a cyclic percentage is resolved against zero > for determining intrinsic size contributions. --- components/layout_2020/flow/inline.rs | 28 ++++------ components/layout_2020/formatting_contexts.rs | 27 +++------- components/layout_2020/sizing.rs | 51 +++++-------------- ...rinsic-size-with-negative-margins.html.ini | 2 - .../flexbox_align-items-stretch-3.html.ini | 2 + 5 files changed, 31 insertions(+), 79 deletions(-) delete mode 100644 tests/wpt/meta/css/CSS2/normal-flow/intrinsic-size-with-negative-margins.html.ini create mode 100644 tests/wpt/meta/css/css-flexbox/flexbox_align-items-stretch-3.html.ini diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index 7dcb04b53f3..9af1a23a213 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -27,7 +27,7 @@ use servo_arc::Arc; use style::computed_values::white_space::T as WhiteSpace; use style::logical_geometry::WritingMode; use style::properties::ComputedValues; -use style::values::computed::{Length, LengthPercentage, Percentage}; +use style::values::computed::Length; use style::values::generics::text::LineHeight; use style::values::specified::text::TextAlignKeyword; use style::values::specified::text::TextDecorationLine; @@ -251,7 +251,6 @@ impl InlineFormattingContext { containing_block_writing_mode: WritingMode, paragraph: ContentSizes, current_line: ContentSizes, - current_line_percentages: Percentage, /// Size for whitepsace pending to be added to this line. pending_whitespace: Length, /// Whether or not this IFC has seen any non-whitespace content. @@ -274,11 +273,15 @@ impl InlineFormattingContext { macro_rules! add { ($condition: ident, $side: ident) => { if inline_box.$condition { - self.add_lengthpercentage(padding.$side); - self.add_length(border.$side); + // For margins and paddings, a cyclic percentage is resolved against zero + // for determining intrinsic size contributions. + // https://drafts.csswg.org/css-sizing-3/#min-percentage-contribution + let zero = Length::zero(); + let mut length = padding.$side.percentage_relative_to(zero) + border.$side; if let Some(lp) = margin.$side.non_auto() { - self.add_lengthpercentage(lp) + length += lp.percentage_relative_to(zero) } + self.add_length(length); } }; } @@ -320,7 +323,7 @@ impl InlineFormattingContext { } }, InlineLevelBox::Atomic(atomic) => { - let (outer, pc) = atomic.outer_inline_content_sizes_and_percentages( + let outer = atomic.outer_inline_content_sizes( self.layout_context, self.containing_block_writing_mode, ); @@ -328,7 +331,6 @@ impl InlineFormattingContext { self.current_line.min_content += self.pending_whitespace + outer.min_content; self.current_line.max_content += outer.max_content; - self.current_line_percentages += pc; self.pending_whitespace = Length::zero(); self.had_non_whitespace_content_yet = true; }, @@ -338,15 +340,6 @@ impl InlineFormattingContext { } } - fn add_lengthpercentage(&mut self, lp: &LengthPercentage) { - if let Some(l) = lp.to_length() { - self.add_length(l); - } - if let Some(p) = lp.to_percentage() { - self.current_line_percentages += p; - } - } - fn add_length(&mut self, l: Length) { self.current_line.min_content += l; self.current_line.max_content += l; @@ -360,8 +353,6 @@ impl InlineFormattingContext { fn forced_line_break(&mut self) { self.line_break_opportunity(); - self.current_line - .adjust_for_pbm_percentages(take(&mut self.current_line_percentages)); self.paragraph .max_content .max_assign(take(&mut self.current_line.max_content)); @@ -375,7 +366,6 @@ impl InlineFormattingContext { containing_block_writing_mode, paragraph: ContentSizes::zero(), current_line: ContentSizes::zero(), - current_line_percentages: Percentage::zero(), pending_whitespace: Length::zero(), had_non_whitespace_content_yet: false, linebreaker: None, diff --git a/components/layout_2020/formatting_contexts.rs b/components/layout_2020/formatting_contexts.rs index aa920936b77..555fd59b229 100644 --- a/components/layout_2020/formatting_contexts.rs +++ b/components/layout_2020/formatting_contexts.rs @@ -17,7 +17,7 @@ use servo_arc::Arc; use std::convert::TryInto; use style::logical_geometry::WritingMode; use style::properties::ComputedValues; -use style::values::computed::{Length, Percentage}; +use style::values::computed::Length; use style::values::specified::text::TextDecorationLine; /// https://drafts.csswg.org/css-display/#independent-formatting-context @@ -151,25 +151,12 @@ impl IndependentFormattingContext { layout_context: &LayoutContext, containing_block_writing_mode: WritingMode, ) -> ContentSizes { - let (mut outer, percentages) = self.outer_inline_content_sizes_and_percentages( - layout_context, - containing_block_writing_mode, - ); - outer.adjust_for_pbm_percentages(percentages); - outer - } - - pub fn outer_inline_content_sizes_and_percentages( - &mut self, - layout_context: &LayoutContext, - containing_block_writing_mode: WritingMode, - ) -> (ContentSizes, Percentage) { match self { Self::NonReplaced(non_replaced) => { let style = &non_replaced.style; let content_sizes = &mut non_replaced.content_sizes; let contents = &non_replaced.contents; - sizing::outer_inline_and_percentages(&style, containing_block_writing_mode, || { + sizing::outer_inline(&style, containing_block_writing_mode, || { content_sizes .get_or_insert_with(|| { contents.inline_content_sizes(layout_context, style.writing_mode) @@ -177,11 +164,11 @@ impl IndependentFormattingContext { .clone() }) }, - Self::Replaced(replaced) => sizing::outer_inline_and_percentages( - &replaced.style, - containing_block_writing_mode, - || replaced.contents.inline_content_sizes(&replaced.style), - ), + Self::Replaced(replaced) => { + sizing::outer_inline(&replaced.style, containing_block_writing_mode, || { + replaced.contents.inline_content_sizes(&replaced.style) + }) + }, } } } diff --git a/components/layout_2020/sizing.rs b/components/layout_2020/sizing.rs index 31e96341132..48f1070d2f2 100644 --- a/components/layout_2020/sizing.rs +++ b/components/layout_2020/sizing.rs @@ -8,7 +8,7 @@ use crate::style_ext::ComputedValuesExt; use style::logical_geometry::WritingMode; use style::properties::longhands::box_sizing::computed_value::T as BoxSizing; use style::properties::ComputedValues; -use style::values::computed::{Length, LengthPercentage, Percentage}; +use style::values::computed::Length; use style::Zero; #[derive(Clone, Debug, Serialize)] @@ -46,19 +46,6 @@ impl ContentSizes { max_content: self.max_content + other.max_content, } } - - /// Relevant to outer intrinsic inline sizes, for percentages from padding and margin. - pub fn adjust_for_pbm_percentages(&mut self, percentages: Percentage) { - // " Note that this may yield an infinite result, but undefined results - // (zero divided by zero) must be treated as zero. " - if self.max_content.px() == 0. { - // Avoid a potential `NaN`. - // Zero is already the result we want regardless of `denominator`. - } else { - let denominator = (1. - percentages.0).max(0.); - self.max_content = Length::new(self.max_content.px() / denominator); - } - } } impl ContentSizes { @@ -73,34 +60,23 @@ pub(crate) fn outer_inline( containing_block_writing_mode: WritingMode, get_content_size: impl FnOnce() -> ContentSizes, ) -> ContentSizes { - let (mut outer, percentages) = - outer_inline_and_percentages(style, containing_block_writing_mode, get_content_size); - outer.adjust_for_pbm_percentages(percentages); - outer -} - -pub(crate) fn outer_inline_and_percentages( - style: &ComputedValues, - containing_block_writing_mode: WritingMode, - get_content_size: impl FnOnce() -> ContentSizes, -) -> (ContentSizes, Percentage) { let padding = style.padding(containing_block_writing_mode); let border = style.border_width(containing_block_writing_mode); let margin = style.margin(containing_block_writing_mode); - let mut pbm_percentages = Percentage::zero(); - let mut decompose = |x: &LengthPercentage| { - pbm_percentages += x.to_percentage().unwrap_or_else(Zero::zero); - x.to_length().unwrap_or_else(Zero::zero) - }; - let pb_lengths = - border.inline_sum() + decompose(padding.inline_start) + decompose(padding.inline_end); - let mut m_lengths = Length::zero(); + // For margins and paddings, a cyclic percentage is resolved against zero + // for determining intrinsic size contributions. + // https://drafts.csswg.org/css-sizing-3/#min-percentage-contribution + let zero = Length::zero(); + let pb_lengths = border.inline_sum() + + padding.inline_start.percentage_relative_to(zero) + + padding.inline_end.percentage_relative_to(zero); + let mut m_lengths = zero; if let Some(m) = margin.inline_start.non_auto() { - m_lengths += decompose(m) + m_lengths += m.percentage_relative_to(zero) } if let Some(m) = margin.inline_end.non_auto() { - m_lengths += decompose(m) + m_lengths += m.percentage_relative_to(zero) } let box_sizing = style.get_position().box_sizing; @@ -114,7 +90,7 @@ pub(crate) fn outer_inline_and_percentages( .min_box_size(containing_block_writing_mode) .inline // Percentages for 'min-width' are treated as zero - .percentage_relative_to(Length::zero()) + .percentage_relative_to(zero) // FIXME: 'auto' is not zero in Flexbox .auto_is(Length::zero); let max_inline_size = style @@ -145,6 +121,5 @@ pub(crate) fn outer_inline_and_percentages( }), }; - let outer = border_box_sizes.map(|s| s + m_lengths); - (outer, pbm_percentages) + border_box_sizes.map(|s| s + m_lengths) } diff --git a/tests/wpt/meta/css/CSS2/normal-flow/intrinsic-size-with-negative-margins.html.ini b/tests/wpt/meta/css/CSS2/normal-flow/intrinsic-size-with-negative-margins.html.ini deleted file mode 100644 index f80d263fca1..00000000000 --- a/tests/wpt/meta/css/CSS2/normal-flow/intrinsic-size-with-negative-margins.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[intrinsic-size-with-negative-margins.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-flexbox/flexbox_align-items-stretch-3.html.ini b/tests/wpt/meta/css/css-flexbox/flexbox_align-items-stretch-3.html.ini new file mode 100644 index 00000000000..9880266ee58 --- /dev/null +++ b/tests/wpt/meta/css/css-flexbox/flexbox_align-items-stretch-3.html.ini @@ -0,0 +1,2 @@ +[flexbox_align-items-stretch-3.html] + expected: FAIL