diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 219fdbdcfb8e..d7b9854668a9 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -20,7 +20,7 @@ use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIter use rayon_croissant::ParallelIteratorExt; use servo_arc::Arc; use style::properties::ComputedValues; -use style::values::computed::{Length, LengthOrAuto}; +use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto}; use style::values::generics::length::MaxSize; use style::Zero; @@ -354,16 +354,16 @@ fn layout_in_flow_non_replaced_block_level<'a>( ) -> FlowLayout, ) -> BoxFragment { let cbis = containing_block.inline_size; - let cbbs = containing_block.block_size.non_auto(); let padding = style.padding().percentages_relative_to(cbis); let border = style.border_width(); let margin = style.margin().percentages_relative_to(cbis); let pb = &padding + &border; let pb_inline_sum = pb.inline_sum(); - let box_size = style.box_size(); - let max_box_size = style.max_box_size(); - let min_box_size = style.min_box_size(); + let box_size = percent_resolved_box_size(style.box_size(), containing_block); + let max_box_size = percent_resolved_max_box_size(style.max_box_size(), containing_block); + let min_box_size = + percent_resolved_box_size(style.min_box_size(), containing_block).auto_is(Length::zero); // https://drafts.csswg.org/css2/visudet.html#min-max-widths let solve_inline_margins = |inline_size| { @@ -376,7 +376,7 @@ fn layout_in_flow_non_replaced_block_level<'a>( ) }; let (mut inline_size, mut inline_margins) = - if let Some(inline_size) = box_size.inline.percentage_relative_to(cbis).non_auto() { + if let Some(inline_size) = box_size.inline.non_auto() { (inline_size, solve_inline_margins(inline_size)) } else { let margin_inline_start = margin.inline_start.auto_is(Length::zero); @@ -385,19 +385,14 @@ fn layout_in_flow_non_replaced_block_level<'a>( let inline_size = cbis - pb_inline_sum - margin_inline_sum; (inline_size, (margin_inline_start, margin_inline_end)) }; - if let MaxSize::LengthPercentage(max_inline_size) = max_box_size.inline { - let max_inline_size = max_inline_size.percentage_relative_to(cbis); + if let Some(max_inline_size) = max_box_size.inline { if inline_size > max_inline_size { inline_size = max_inline_size; inline_margins = solve_inline_margins(inline_size); } } - let min_inline_size = min_box_size - .inline - .percentage_relative_to(cbis) - .auto_is(Length::zero); - if inline_size < min_inline_size { - inline_size = min_inline_size; + if inline_size < min_box_size.inline { + inline_size = min_box_size.inline; inline_margins = solve_inline_margins(inline_size); } @@ -409,19 +404,9 @@ fn layout_in_flow_non_replaced_block_level<'a>( }; // https://drafts.csswg.org/css2/visudet.html#min-max-heights - let max_block_size = match max_box_size.block { - MaxSize::LengthPercentage(max_block_size) => { - max_block_size.maybe_percentage_relative_to(cbbs) - }, - MaxSize::None => None, - }; - let min_block_size = min_box_size - .block - .maybe_percentage_relative_to(cbbs) - .auto_is(Length::zero); - let mut block_size = box_size.block.maybe_percentage_relative_to(cbbs); + let mut block_size = box_size.block; if let LengthOrAuto::LengthPercentage(ref mut block_size) = block_size { - *block_size = clamp_between_extremums(*block_size, min_block_size, max_block_size); + *block_size = clamp_between_extremums(*block_size, min_box_size.block, max_box_size.block); } let containing_block_for_children = ContainingBlock { @@ -440,7 +425,7 @@ fn layout_in_flow_non_replaced_block_level<'a>( pb.block_start == Length::zero(), ); let this_end_margin_can_collapse_with_children = block_size == LengthOrAuto::Auto && - min_block_size == Length::zero() && + min_box_size.block == Length::zero() && pb.block_end == Length::zero() && block_level_kind == BlockLevelKind::SameFormattingContextBlock; let mut nested_abspos = vec![]; @@ -487,8 +472,8 @@ fn layout_in_flow_non_replaced_block_level<'a>( let block_size = block_size.auto_is(|| { clamp_between_extremums( flow_layout.content_block_size, - min_block_size, - max_block_size, + min_box_size.block, + max_box_size.block, ) }); let content_rect = Rect { @@ -531,7 +516,6 @@ fn layout_in_flow_replaced_block_level<'a>( replaced: &ReplacedContent, ) -> BoxFragment { let cbis = containing_block.inline_size; - let cbbs = containing_block.block_size.non_auto(); let padding = style.padding().percentages_relative_to(cbis); let border = style.border_width(); let computed_margin = style.margin().percentages_relative_to(cbis); @@ -542,41 +526,20 @@ fn layout_in_flow_replaced_block_level<'a>( // FIXME(nox): This can divide by zero. let intrinsic_ratio = intrinsic_size.inline.px() / intrinsic_size.block.px(); - let box_size = style.box_size(); - let min_box_size = style.min_box_size(); - let max_box_size = style.max_box_size(); - - let inline_size = box_size.inline.percentage_relative_to(cbis); - let min_inline_size = min_box_size - .inline - .percentage_relative_to(cbis) - .auto_is(Length::zero); - let max_inline_size = match max_box_size.inline { - MaxSize::LengthPercentage(max_inline_size) => { - Some(max_inline_size.percentage_relative_to(cbis)) - }, - MaxSize::None => None, - }; - let block_size = box_size.block.maybe_percentage_relative_to(cbbs); - let min_block_size = min_box_size - .block - .maybe_percentage_relative_to(cbbs) - .auto_is(Length::zero); - let max_block_size = match max_box_size.block { - MaxSize::LengthPercentage(max_block_size) => { - max_block_size.maybe_percentage_relative_to(cbbs) - }, - MaxSize::None => None, - }; + let box_size = percent_resolved_box_size(style.box_size(), containing_block); + let min_box_size = + percent_resolved_box_size(style.min_box_size(), containing_block).auto_is(Length::zero); + let max_box_size = percent_resolved_max_box_size(style.max_box_size(), containing_block); + let clamp = |inline_size, block_size| { ( - clamp_between_extremums(inline_size, min_inline_size, max_inline_size), - clamp_between_extremums(block_size, min_block_size, max_block_size), + clamp_between_extremums(inline_size, min_box_size.inline, max_box_size.inline), + clamp_between_extremums(block_size, min_box_size.block, max_box_size.block), ) }; // https://drafts.csswg.org/css2/visudet.html#min-max-widths // https://drafts.csswg.org/css2/visudet.html#min-max-heights - let (inline_size, block_size) = match (inline_size, block_size) { + let (inline_size, block_size) = match (box_size.inline, box_size.block) { (LengthOrAuto::LengthPercentage(inline), LengthOrAuto::LengthPercentage(block)) => { clamp(inline, block) }, @@ -605,39 +568,35 @@ fn layout_in_flow_replaced_block_level<'a>( } }; match ( - violation(intrinsic_size.inline, min_inline_size, max_inline_size), - violation(intrinsic_size.block, min_block_size, max_block_size), + violation( + intrinsic_size.inline, + min_box_size.inline, + max_box_size.inline, + ), + violation(intrinsic_size.block, min_box_size.block, max_box_size.block), ) { // Row 1. (Violation::None, Violation::None) => (intrinsic_size.inline, intrinsic_size.block), // Row 2. (Violation::Above(max_inline_size), Violation::None) => { - let block_size = (max_inline_size / intrinsic_ratio).max(min_block_size); + let block_size = (max_inline_size / intrinsic_ratio).max(min_box_size.block); (max_inline_size, block_size) }, // Row 3. (Violation::Below(min_inline_size), Violation::None) => { - let mut block_size = min_inline_size / intrinsic_ratio; - if let Some(max_block_size) = max_block_size { - if block_size > max_block_size { - block_size = max_block_size; - } - } + let block_size = + clamp_below_max(min_inline_size / intrinsic_ratio, max_box_size.block); (min_inline_size, block_size) }, // Row 4. (Violation::None, Violation::Above(max_block_size)) => { - let inline_size = (max_block_size * intrinsic_ratio).max(min_inline_size); + let inline_size = (max_block_size * intrinsic_ratio).max(min_box_size.inline); (inline_size, max_block_size) }, // Row 5. (Violation::None, Violation::Below(min_block_size)) => { - let mut inline_size = min_block_size * intrinsic_ratio; - if let Some(max_inline_size) = max_inline_size { - if inline_size > max_inline_size { - inline_size = max_inline_size; - } - } + let inline_size = + clamp_below_max(min_block_size * intrinsic_ratio, max_box_size.inline); (inline_size, min_block_size) }, // Rows 6-7. @@ -646,11 +605,13 @@ fn layout_in_flow_replaced_block_level<'a>( max_block_size.px() / intrinsic_size.block.px() { // Row 6. - let block_size = (max_inline_size / intrinsic_ratio).max(min_block_size); + let block_size = + (max_inline_size / intrinsic_ratio).max(min_box_size.block); (max_inline_size, block_size) } else { // Row 7. - let inline_size = (max_block_size * intrinsic_ratio).max(min_inline_size); + let inline_size = + (max_block_size * intrinsic_ratio).max(min_box_size.inline); (inline_size, max_block_size) } }, @@ -660,21 +621,13 @@ fn layout_in_flow_replaced_block_level<'a>( min_block_size.px() / intrinsic_size.block.px() { // Row 8. - let mut inline_size = min_block_size * intrinsic_ratio; - if let Some(max_inline_size) = max_inline_size { - if inline_size > max_inline_size { - inline_size = max_inline_size; - } - } + let inline_size = + clamp_below_max(min_block_size * intrinsic_ratio, max_box_size.inline); (inline_size, min_block_size) } else { // Row 9. - let mut block_size = min_inline_size / intrinsic_ratio; - if let Some(max_block_size) = max_block_size { - if block_size > max_block_size { - block_size = max_block_size; - } - } + let block_size = + clamp_below_max(min_inline_size / intrinsic_ratio, max_box_size.block); (min_inline_size, block_size) } }, @@ -755,11 +708,44 @@ fn solve_inline_margins_for_in_flow_block_level( } } -fn clamp_between_extremums(mut size: Length, min_size: Length, max_size: Option) -> Length { - if let Some(max_size) = max_size { - if size > max_size { - size = max_size; - } +fn clamp_between_extremums(size: Length, min_size: Length, max_size: Option) -> Length { + clamp_below_max(size, max_size).max(min_size) +} + +fn clamp_below_max(size: Length, max_size: Option) -> Length { + max_size.map_or(size, |max_size| size.min(max_size)) +} + +fn percent_resolved_box_size( + box_size: Vec2, + containing_block: &ContainingBlock, +) -> Vec2 { + Vec2 { + inline: box_size + .inline + .percentage_relative_to(containing_block.inline_size), + block: box_size + .block + .maybe_percentage_relative_to(containing_block.block_size.non_auto()), + } +} + +fn percent_resolved_max_box_size( + max_box_size: Vec2>, + containing_block: &ContainingBlock, +) -> Vec2> { + Vec2 { + inline: match max_box_size.inline { + MaxSize::LengthPercentage(max_inline_size) => { + Some(max_inline_size.percentage_relative_to(containing_block.inline_size)) + }, + MaxSize::None => None, + }, + block: match max_box_size.block { + MaxSize::LengthPercentage(max_block_size) => { + max_block_size.maybe_percentage_relative_to(containing_block.block_size.non_auto()) + }, + MaxSize::None => None, + }, } - size.max(min_size) } diff --git a/components/layout_2020/geom.rs b/components/layout_2020/geom.rs index d75a16345617..39c7cb331e4e 100644 --- a/components/layout_2020/geom.rs +++ b/components/layout_2020/geom.rs @@ -141,6 +141,15 @@ impl flow_relative::Vec2 { } } +impl flow_relative::Vec2 { + pub fn auto_is(&self, f: impl Fn() -> Length) -> flow_relative::Vec2 { + flow_relative::Vec2 { + inline: self.inline.auto_is(&f), + block: self.block.auto_is(&f), + } + } +} + impl flow_relative::Rect { pub fn zero() -> Self { Self {