diff --git a/components/layout_2020/flow/construct.rs b/components/layout_2020/flow/construct.rs index 606628d5744..c02dcd08fd7 100644 --- a/components/layout_2020/flow/construct.rs +++ b/components/layout_2020/flow/construct.rs @@ -10,7 +10,7 @@ use crate::flow::inline::{InlineBox, InlineFormattingContext, InlineLevelBox, Te use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox}; use crate::formatting_contexts::IndependentFormattingContext; use crate::positioned::AbsolutelyPositionedBox; -use crate::sizing::{outer_inline_content_sizes, ContentSizes, ContentSizesRequest}; +use crate::sizing::{BoxContentSizes, ContentSizes, ContentSizesRequest}; use crate::style_ext::{ComputedValuesExt, DisplayGeneratingBox, DisplayInside, DisplayOutside}; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use rayon_croissant::ParallelIteratorExt; @@ -25,7 +25,7 @@ impl BlockFormattingContext { style: &Arc, contents: NonReplacedContents>, content_sizes: ContentSizesRequest, - ) -> (Self, Option) { + ) -> (Self, BoxContentSizes) { let (contents, contains_floats, inline_content_sizes) = BlockContainer::construct(context, style, contents, content_sizes); // FIXME: add contribution to `inline_content_sizes` of floats in this formatting context @@ -134,7 +134,7 @@ impl BlockContainer { block_container_style: &Arc, contents: NonReplacedContents>, content_sizes: ContentSizesRequest, - ) -> (BlockContainer, ContainsFloats, Option) { + ) -> (BlockContainer, ContainsFloats, BoxContentSizes) { let mut builder = BlockContainerBuilder { context, block_container_style, @@ -155,7 +155,7 @@ impl BlockContainer { .is_empty() { if builder.block_level_boxes.is_empty() { - let inline_content_sizes = content_sizes.if_requests_inline(|| { + let content_sizes = content_sizes.compute(|| { builder .ongoing_inline_formatting_context .inline_content_sizes(context) @@ -163,7 +163,7 @@ impl BlockContainer { let container = BlockContainer::InlineFormattingContext( builder.ongoing_inline_formatting_context, ); - return (container, builder.contains_floats, inline_content_sizes); + return (container, builder.contains_floats, content_sizes); } builder.end_ongoing_inline_formatting_context(); } @@ -212,9 +212,8 @@ impl BlockContainer { contains_floats, outer_content_sizes_of_children, } = target; - let inline_content_sizes = - content_sizes.if_requests_inline(|| outer_content_sizes_of_children); - (container, contains_floats, inline_content_sizes) + let content_sizes = content_sizes.compute(|| outer_content_sizes_of_children); + (container, contains_floats, content_sizes) } } @@ -586,7 +585,7 @@ where ) -> (Arc, ContainsFloats) { match self { IntermediateBlockLevelBox::SameFormattingContextBlock { style, contents } => { - let (contents, contains_floats, inline_content_sizes) = contents.finish( + let (contents, contains_floats, box_content_sizes) = contents.finish( context, &style, ContentSizesRequest::inline_if( @@ -595,7 +594,7 @@ where ), ); if let Some(to) = max_assign_in_flow_outer_content_sizes_to { - to.max_assign(&outer_inline_content_sizes(&style, &inline_content_sizes)) + to.max_assign(&box_content_sizes.outer_inline(&style)) } let block_level_box = Arc::new(BlockLevelBox::SameFormattingContextBlock { contents, style }); @@ -618,10 +617,7 @@ where content_sizes, ); if let Some(to) = max_assign_in_flow_outer_content_sizes_to { - to.max_assign(&outer_inline_content_sizes( - &contents.style, - &contents.inline_content_sizes, - )) + to.max_assign(&contents.content_sizes.outer_inline(&contents.style)) } ( Arc::new(BlockLevelBox::Independent(contents)), @@ -661,21 +657,20 @@ where context: &LayoutContext, style: &Arc, content_sizes: ContentSizesRequest, - ) -> (BlockContainer, ContainsFloats, Option) { + ) -> (BlockContainer, ContainsFloats, BoxContentSizes) { match self { IntermediateBlockContainer::Deferred { contents } => { BlockContainer::construct(context, style, contents, content_sizes) }, IntermediateBlockContainer::InlineFormattingContext(ifc) => { - let inline_content_sizes = - content_sizes.if_requests_inline(|| ifc.inline_content_sizes(context)); + let content_sizes = content_sizes.compute(|| ifc.inline_content_sizes(context)); // If that inline formatting context contained any float, those // were already taken into account during the first phase of // box construction. ( BlockContainer::InlineFormattingContext(ifc), ContainsFloats::No, - inline_content_sizes, + content_sizes, ) }, } diff --git a/components/layout_2020/flow/inline.rs b/components/layout_2020/flow/inline.rs index fe66d486e9a..4c6e364a8fa 100644 --- a/components/layout_2020/flow/inline.rs +++ b/components/layout_2020/flow/inline.rs @@ -10,7 +10,7 @@ use crate::fragments::CollapsedBlockMargins; use crate::fragments::{AnonymousFragment, BoxFragment, Fragment, TextFragment}; use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::positioned::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment}; -use crate::sizing::{outer_inline_content_sizes_and_percentages, shrink_to_fit, ContentSizes}; +use crate::sizing::ContentSizes; use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside}; use crate::{relative_adjustement, ContainingBlock}; use app_units::Au; @@ -139,10 +139,9 @@ impl InlineFormattingContext { } }, InlineLevelBox::Atomic(atomic) => { - let (outer, pc) = outer_inline_content_sizes_and_percentages( - &atomic.style, - &atomic.inline_content_sizes, - ); + let (outer, pc) = atomic + .content_sizes + .outer_inline_and_percentages(&atomic.style); self.current_line.min_content += outer.min_content; self.current_line.max_content += outer.max_content; self.current_line_percentages += pc; @@ -439,7 +438,7 @@ fn layout_atomic<'box_tree>( let box_size = atomic.style.box_size(); let inline_size = box_size.inline.percentage_relative_to(cbis).auto_is(|| { let available_size = cbis - pbm.inline_sum(); - shrink_to_fit(&atomic.inline_content_sizes, available_size) + atomic.content_sizes.shrink_to_fit(available_size) }); let block_size = box_size .block diff --git a/components/layout_2020/formatting_contexts.rs b/components/layout_2020/formatting_contexts.rs index 8f62d3d8d6b..d7477182437 100644 --- a/components/layout_2020/formatting_contexts.rs +++ b/components/layout_2020/formatting_contexts.rs @@ -8,7 +8,7 @@ use crate::flow::BlockFormattingContext; use crate::fragments::Fragment; use crate::positioned::AbsolutelyPositionedFragment; use crate::replaced::ReplacedContent; -use crate::sizing::{ContentSizes, ContentSizesRequest}; +use crate::sizing::{BoxContentSizes, ContentSizesRequest}; use crate::style_ext::DisplayInside; use crate::ContainingBlock; use servo_arc::Arc; @@ -22,7 +22,7 @@ pub(crate) struct IndependentFormattingContext { pub style: Arc, /// If it was requested during construction - pub inline_content_sizes: Option, + pub content_sizes: BoxContentSizes, contents: IndependentFormattingContextContents, } @@ -58,27 +58,30 @@ impl IndependentFormattingContext { content_sizes: ContentSizesRequest, ) -> Self { use self::IndependentFormattingContextContents as Contents; - let (contents, inline_content_sizes) = match contents.try_into() { + let (contents, content_sizes) = match contents.try_into() { Ok(non_replaced) => match display_inside { DisplayInside::Flow | DisplayInside::FlowRoot => { - let (bfc, inline_content_sizes) = BlockFormattingContext::construct( + let (bfc, box_content_sizes) = BlockFormattingContext::construct( context, &style, non_replaced, content_sizes, ); - (Contents::Flow(bfc), inline_content_sizes) + (Contents::Flow(bfc), box_content_sizes) }, }, Err(replaced) => { - let inline_content_sizes = None; // Unused by layout code - (Contents::Replaced(replaced), inline_content_sizes) + // The `content_sizes` field is not used by layout code: + ( + Contents::Replaced(replaced), + BoxContentSizes::NoneWereRequested, + ) }, }; Self { style, contents, - inline_content_sizes, + content_sizes, } } diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index f2a6551f6c1..06d88709165 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -7,7 +7,7 @@ use crate::dom_traversal::{Contents, NodeExt}; use crate::formatting_contexts::IndependentFormattingContext; use crate::fragments::{AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment}; use crate::geom::flow_relative::{Rect, Sides, Vec2}; -use crate::sizing::{shrink_to_fit, ContentSizesRequest}; +use crate::sizing::ContentSizesRequest; use crate::style_ext::{ComputedValuesExt, Direction, DisplayInside, WritingMode}; use crate::{ContainingBlock, DefiniteContainingBlock}; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; @@ -295,10 +295,10 @@ impl<'a> AbsolutelyPositionedFragment<'a> { // FIXME: implement https://drafts.csswg.org/css2/visudet.html#abs-replaced-width available_size } else { - shrink_to_fit( - &self.absolutely_positioned_box.contents.inline_content_sizes, - available_size, - ) + self.absolutely_positioned_box + .contents + .content_sizes + .shrink_to_fit(available_size) } }); diff --git a/components/layout_2020/sizing.rs b/components/layout_2020/sizing.rs index 1a036dbd083..75c13b1dcb5 100644 --- a/components/layout_2020/sizing.rs +++ b/components/layout_2020/sizing.rs @@ -38,6 +38,13 @@ impl ContentSizesRequest { Self::None => None, } } + + pub fn compute(self, compute_inline: impl FnOnce() -> ContentSizes) -> BoxContentSizes { + match self { + Self::Inline => BoxContentSizes::Inline(compute_inline()), + Self::None => BoxContentSizes::NoneWereRequested, + } + } } #[derive(Clone, Debug)] @@ -74,69 +81,72 @@ impl ContentSizes { } } -/// https://dbaron.org/css/intrinsic/#outer-intrinsic -pub(crate) fn outer_inline_content_sizes( - style: &ComputedValues, - inner_content_sizes: &Option, -) -> ContentSizes { - let (mut outer, percentages) = - outer_inline_content_sizes_and_percentages(style, inner_content_sizes); - outer.adjust_for_pbm_percentages(percentages); - outer +/// Optional min/max-content for storage in the box tree +#[derive(Debug)] +pub(crate) enum BoxContentSizes { + NoneWereRequested, // … during box construction + Inline(ContentSizes), } -pub(crate) fn outer_inline_content_sizes_and_percentages( - style: &ComputedValues, - inner_content_sizes: &Option, -) -> (ContentSizes, Percentage) { - // FIXME: account for 'min-width', 'max-width', 'box-sizing' +impl BoxContentSizes { + fn expect_inline(&self) -> &ContentSizes { + match self { + Self::NoneWereRequested => panic!("Accessing content size that was not requested"), + Self::Inline(s) => s, + } + } - let inline_size = style.box_size().inline; - // Percentages for 'width' are treated as 'auto' - let inline_size = inline_size.map(|lp| lp.as_length()); - // The (inner) min/max-content are only used for 'auto' - let mut outer = match inline_size.non_auto().flatten() { - None => expect(inner_content_sizes).clone(), - Some(length) => ContentSizes { - min_content: length, - max_content: length, - }, - }; + /// https://dbaron.org/css/intrinsic/#outer-intrinsic + pub fn outer_inline(&self, style: &ComputedValues) -> ContentSizes { + let (mut outer, percentages) = self.outer_inline_and_percentages(style); + outer.adjust_for_pbm_percentages(percentages); + outer + } - let mut pbm_lengths = Length::zero(); - let mut pbm_percentages = Percentage::zero(); - let padding = style.padding(); - let border = style.border_width(); - let margin = style.margin(); - pbm_lengths += border.inline_sum(); - let mut add = |x: LengthPercentage| { - pbm_lengths += x.length_component(); - pbm_percentages += x.percentage_component(); - }; - add(padding.inline_start); - add(padding.inline_end); - margin.inline_start.non_auto().map(&mut add); - margin.inline_end.non_auto().map(&mut add); + pub(crate) fn outer_inline_and_percentages( + &self, + style: &ComputedValues, + ) -> (ContentSizes, Percentage) { + // FIXME: account for 'min-width', 'max-width', 'box-sizing' - outer.min_content += pbm_lengths; - outer.max_content += pbm_lengths; + let inline_size = style.box_size().inline; + // Percentages for 'width' are treated as 'auto' + let inline_size = inline_size.map(|lp| lp.as_length()); + // The (inner) min/max-content are only used for 'auto' + let mut outer = match inline_size.non_auto().flatten() { + None => self.expect_inline().clone(), + Some(length) => ContentSizes { + min_content: length, + max_content: length, + }, + }; - (outer, pbm_percentages) -} - -/// https://drafts.csswg.org/css2/visudet.html#shrink-to-fit-float -pub(crate) fn shrink_to_fit( - content_sizes: &Option, - available_size: Length, -) -> Length { - let content_sizes = expect(content_sizes); - available_size - .max(content_sizes.min_content) - .min(content_sizes.max_content) -} - -fn expect(content_sizes: &Option) -> &ContentSizes { - content_sizes - .as_ref() - .expect("Accessing content size that was not requested") + let mut pbm_lengths = Length::zero(); + let mut pbm_percentages = Percentage::zero(); + let padding = style.padding(); + let border = style.border_width(); + let margin = style.margin(); + pbm_lengths += border.inline_sum(); + let mut add = |x: LengthPercentage| { + pbm_lengths += x.length_component(); + pbm_percentages += x.percentage_component(); + }; + 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 += pbm_lengths; + outer.max_content += pbm_lengths; + + (outer, pbm_percentages) + } + + /// https://drafts.csswg.org/css2/visudet.html#shrink-to-fit-float + pub(crate) fn shrink_to_fit(&self, available_size: Length) -> Length { + let inline = self.expect_inline(); + available_size + .max(inline.min_content) + .min(inline.max_content) + } }