diff --git a/components/layout_2020/intrinsic.rs b/components/layout_2020/intrinsic.rs new file mode 100644 index 00000000000..1b811928f86 --- /dev/null +++ b/components/layout_2020/intrinsic.rs @@ -0,0 +1,69 @@ +use crate::style_ext::ComputedValuesExt; +use style::Zero; +use style::properties::ComputedValues; +use style::values::computed::{Length, LengthPercentage}; + +#[derive(Debug, Clone)] +pub(crate) struct IntrinsicSizes { + pub min_content: Length, + pub max_content: Length, +} + +impl IntrinsicSizes { + pub fn zero() -> Self { + Self { + min_content: Length::zero(), + max_content: Length::zero(), + } + } +} + +/// https://dbaron.org/css/intrinsic/#outer-intrinsic +pub(crate) fn outer_intrinsic_inline_sizes( + style: &ComputedValues, + get_inner_intrinsic_sizes: &dyn Fn() -> IntrinsicSizes, +) -> IntrinsicSizes { + // FIXME: account for 'min-width', 'max-width', 'box-sizing' + + let specified = style.box_size().inline; + // Percentages for 'width' are treated as 'auto' + let specified = specified.map(|lp| lp.as_length()); + // The (inner) min/max-content are only used for 'auto' + let mut outer = match specified.non_auto().flatten() { + None => get_inner_intrinsic_sizes(), + Some(length) => IntrinsicSizes { + min_content: length, + max_content: length, + } + }; + + let mut bpm_lengths = Length::zero(); + let mut bpm_percentages = 0.; + let padding = style.padding(); + let border = style.border_width(); + let margin = style.margin(); + bpm_lengths += border.inline_start; + bpm_lengths += border.inline_end; + let mut add = |x: LengthPercentage| { + bpm_lengths += x.length_component(); + bpm_percentages += x.percentage(); + }; + add(padding.inline_start); + add(padding.inline_end); + margin.inline_start.non_auto().map(&mut add); + margin.inline_end.non_auto().map(&mut add); + + outer.min_content += bpm_lengths; + outer.max_content += bpm_lengths; + // " Note that this may yield an infinite result, but undefined results + // (zero divided by zero) must be treated as zero. " + if outer.max_content.px() == 0. { + // Avoid a potential `NaN`. + // Zero is already the result we want regardless of `denominator`. + } else { + let denominator = (1. - bpm_percentages).max(0.); + outer.max_content = Length::new(outer.max_content.px() / denominator); + } + + outer +} diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index 53cf7cbd696..59a3131142c 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -186,6 +186,16 @@ impl LengthPercentage { } } + /// Returns the length component if this could be represented as a + /// non-calc length. + pub fn as_length(&self) -> Option { + if !self.has_percentage { + Some(self.length_component()) + } else { + None + } + } + /// Returns the percentage component if this could be represented as a /// non-calc percentage. pub fn as_percentage(&self) -> Option { diff --git a/components/style/values/generics/length.rs b/components/style/values/generics/length.rs index d9cc2396f38..4183f40a942 100644 --- a/components/style/values/generics/length.rs +++ b/components/style/values/generics/length.rs @@ -92,7 +92,7 @@ where } /// Maps the length of this value. - pub fn map(&self, f: impl FnOnce(LengthPercentage) -> LengthPercentage) -> Self { + pub fn map(&self, f: impl FnOnce(LengthPercentage) -> T) -> LengthPercentageOrAuto { match self { LengthPercentageOrAuto::LengthPercentage(l) => { LengthPercentageOrAuto::LengthPercentage(f(l.clone()))