Use a new BoxContentSizes enum instead of Option<ContentSizes>

This commit is contained in:
Simon Sapin 2019-12-04 15:36:05 +01:00
parent 38e8fd1e99
commit dd9dfc66e3
5 changed files with 103 additions and 96 deletions

View file

@ -10,7 +10,7 @@ use crate::flow::inline::{InlineBox, InlineFormattingContext, InlineLevelBox, Te
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox}; use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
use crate::formatting_contexts::IndependentFormattingContext; use crate::formatting_contexts::IndependentFormattingContext;
use crate::positioned::AbsolutelyPositionedBox; 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 crate::style_ext::{ComputedValuesExt, DisplayGeneratingBox, DisplayInside, DisplayOutside};
use rayon::iter::{IntoParallelIterator, ParallelIterator}; use rayon::iter::{IntoParallelIterator, ParallelIterator};
use rayon_croissant::ParallelIteratorExt; use rayon_croissant::ParallelIteratorExt;
@ -25,7 +25,7 @@ impl BlockFormattingContext {
style: &Arc<ComputedValues>, style: &Arc<ComputedValues>,
contents: NonReplacedContents<impl NodeExt<'dom>>, contents: NonReplacedContents<impl NodeExt<'dom>>,
content_sizes: ContentSizesRequest, content_sizes: ContentSizesRequest,
) -> (Self, Option<ContentSizes>) { ) -> (Self, BoxContentSizes) {
let (contents, contains_floats, inline_content_sizes) = let (contents, contains_floats, inline_content_sizes) =
BlockContainer::construct(context, style, contents, content_sizes); BlockContainer::construct(context, style, contents, content_sizes);
// FIXME: add contribution to `inline_content_sizes` of floats in this formatting context // FIXME: add contribution to `inline_content_sizes` of floats in this formatting context
@ -134,7 +134,7 @@ impl BlockContainer {
block_container_style: &Arc<ComputedValues>, block_container_style: &Arc<ComputedValues>,
contents: NonReplacedContents<impl NodeExt<'dom>>, contents: NonReplacedContents<impl NodeExt<'dom>>,
content_sizes: ContentSizesRequest, content_sizes: ContentSizesRequest,
) -> (BlockContainer, ContainsFloats, Option<ContentSizes>) { ) -> (BlockContainer, ContainsFloats, BoxContentSizes) {
let mut builder = BlockContainerBuilder { let mut builder = BlockContainerBuilder {
context, context,
block_container_style, block_container_style,
@ -155,7 +155,7 @@ impl BlockContainer {
.is_empty() .is_empty()
{ {
if builder.block_level_boxes.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 builder
.ongoing_inline_formatting_context .ongoing_inline_formatting_context
.inline_content_sizes(context) .inline_content_sizes(context)
@ -163,7 +163,7 @@ impl BlockContainer {
let container = BlockContainer::InlineFormattingContext( let container = BlockContainer::InlineFormattingContext(
builder.ongoing_inline_formatting_context, 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(); builder.end_ongoing_inline_formatting_context();
} }
@ -212,9 +212,8 @@ impl BlockContainer {
contains_floats, contains_floats,
outer_content_sizes_of_children, outer_content_sizes_of_children,
} = target; } = target;
let inline_content_sizes = let content_sizes = content_sizes.compute(|| outer_content_sizes_of_children);
content_sizes.if_requests_inline(|| outer_content_sizes_of_children); (container, contains_floats, content_sizes)
(container, contains_floats, inline_content_sizes)
} }
} }
@ -586,7 +585,7 @@ where
) -> (Arc<BlockLevelBox>, ContainsFloats) { ) -> (Arc<BlockLevelBox>, ContainsFloats) {
match self { match self {
IntermediateBlockLevelBox::SameFormattingContextBlock { style, contents } => { IntermediateBlockLevelBox::SameFormattingContextBlock { style, contents } => {
let (contents, contains_floats, inline_content_sizes) = contents.finish( let (contents, contains_floats, box_content_sizes) = contents.finish(
context, context,
&style, &style,
ContentSizesRequest::inline_if( ContentSizesRequest::inline_if(
@ -595,7 +594,7 @@ where
), ),
); );
if let Some(to) = max_assign_in_flow_outer_content_sizes_to { 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 = let block_level_box =
Arc::new(BlockLevelBox::SameFormattingContextBlock { contents, style }); Arc::new(BlockLevelBox::SameFormattingContextBlock { contents, style });
@ -618,10 +617,7 @@ where
content_sizes, content_sizes,
); );
if let Some(to) = max_assign_in_flow_outer_content_sizes_to { if let Some(to) = max_assign_in_flow_outer_content_sizes_to {
to.max_assign(&outer_inline_content_sizes( to.max_assign(&contents.content_sizes.outer_inline(&contents.style))
&contents.style,
&contents.inline_content_sizes,
))
} }
( (
Arc::new(BlockLevelBox::Independent(contents)), Arc::new(BlockLevelBox::Independent(contents)),
@ -661,21 +657,20 @@ where
context: &LayoutContext, context: &LayoutContext,
style: &Arc<ComputedValues>, style: &Arc<ComputedValues>,
content_sizes: ContentSizesRequest, content_sizes: ContentSizesRequest,
) -> (BlockContainer, ContainsFloats, Option<ContentSizes>) { ) -> (BlockContainer, ContainsFloats, BoxContentSizes) {
match self { match self {
IntermediateBlockContainer::Deferred { contents } => { IntermediateBlockContainer::Deferred { contents } => {
BlockContainer::construct(context, style, contents, content_sizes) BlockContainer::construct(context, style, contents, content_sizes)
}, },
IntermediateBlockContainer::InlineFormattingContext(ifc) => { IntermediateBlockContainer::InlineFormattingContext(ifc) => {
let inline_content_sizes = let content_sizes = content_sizes.compute(|| ifc.inline_content_sizes(context));
content_sizes.if_requests_inline(|| ifc.inline_content_sizes(context));
// If that inline formatting context contained any float, those // If that inline formatting context contained any float, those
// were already taken into account during the first phase of // were already taken into account during the first phase of
// box construction. // box construction.
( (
BlockContainer::InlineFormattingContext(ifc), BlockContainer::InlineFormattingContext(ifc),
ContainsFloats::No, ContainsFloats::No,
inline_content_sizes, content_sizes,
) )
}, },
} }

View file

@ -10,7 +10,7 @@ use crate::fragments::CollapsedBlockMargins;
use crate::fragments::{AnonymousFragment, BoxFragment, Fragment, TextFragment}; use crate::fragments::{AnonymousFragment, BoxFragment, Fragment, TextFragment};
use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::positioned::{AbsolutelyPositionedBox, AbsolutelyPositionedFragment}; 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::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside};
use crate::{relative_adjustement, ContainingBlock}; use crate::{relative_adjustement, ContainingBlock};
use app_units::Au; use app_units::Au;
@ -139,10 +139,9 @@ impl InlineFormattingContext {
} }
}, },
InlineLevelBox::Atomic(atomic) => { InlineLevelBox::Atomic(atomic) => {
let (outer, pc) = outer_inline_content_sizes_and_percentages( let (outer, pc) = atomic
&atomic.style, .content_sizes
&atomic.inline_content_sizes, .outer_inline_and_percentages(&atomic.style);
);
self.current_line.min_content += outer.min_content; self.current_line.min_content += outer.min_content;
self.current_line.max_content += outer.max_content; self.current_line.max_content += outer.max_content;
self.current_line_percentages += pc; self.current_line_percentages += pc;
@ -439,7 +438,7 @@ fn layout_atomic<'box_tree>(
let box_size = atomic.style.box_size(); let box_size = atomic.style.box_size();
let inline_size = box_size.inline.percentage_relative_to(cbis).auto_is(|| { let inline_size = box_size.inline.percentage_relative_to(cbis).auto_is(|| {
let available_size = cbis - pbm.inline_sum(); 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 let block_size = box_size
.block .block

View file

@ -8,7 +8,7 @@ use crate::flow::BlockFormattingContext;
use crate::fragments::Fragment; use crate::fragments::Fragment;
use crate::positioned::AbsolutelyPositionedFragment; use crate::positioned::AbsolutelyPositionedFragment;
use crate::replaced::ReplacedContent; use crate::replaced::ReplacedContent;
use crate::sizing::{ContentSizes, ContentSizesRequest}; use crate::sizing::{BoxContentSizes, ContentSizesRequest};
use crate::style_ext::DisplayInside; use crate::style_ext::DisplayInside;
use crate::ContainingBlock; use crate::ContainingBlock;
use servo_arc::Arc; use servo_arc::Arc;
@ -22,7 +22,7 @@ pub(crate) struct IndependentFormattingContext {
pub style: Arc<ComputedValues>, pub style: Arc<ComputedValues>,
/// If it was requested during construction /// If it was requested during construction
pub inline_content_sizes: Option<ContentSizes>, pub content_sizes: BoxContentSizes,
contents: IndependentFormattingContextContents, contents: IndependentFormattingContextContents,
} }
@ -58,27 +58,30 @@ impl IndependentFormattingContext {
content_sizes: ContentSizesRequest, content_sizes: ContentSizesRequest,
) -> Self { ) -> Self {
use self::IndependentFormattingContextContents as Contents; 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 { Ok(non_replaced) => match display_inside {
DisplayInside::Flow | DisplayInside::FlowRoot => { DisplayInside::Flow | DisplayInside::FlowRoot => {
let (bfc, inline_content_sizes) = BlockFormattingContext::construct( let (bfc, box_content_sizes) = BlockFormattingContext::construct(
context, context,
&style, &style,
non_replaced, non_replaced,
content_sizes, content_sizes,
); );
(Contents::Flow(bfc), inline_content_sizes) (Contents::Flow(bfc), box_content_sizes)
}, },
}, },
Err(replaced) => { Err(replaced) => {
let inline_content_sizes = None; // Unused by layout code // The `content_sizes` field is not used by layout code:
(Contents::Replaced(replaced), inline_content_sizes) (
Contents::Replaced(replaced),
BoxContentSizes::NoneWereRequested,
)
}, },
}; };
Self { Self {
style, style,
contents, contents,
inline_content_sizes, content_sizes,
} }
} }

View file

@ -7,7 +7,7 @@ use crate::dom_traversal::{Contents, NodeExt};
use crate::formatting_contexts::IndependentFormattingContext; use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::{AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment}; use crate::fragments::{AnonymousFragment, BoxFragment, CollapsedBlockMargins, Fragment};
use crate::geom::flow_relative::{Rect, Sides, Vec2}; 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::style_ext::{ComputedValuesExt, Direction, DisplayInside, WritingMode};
use crate::{ContainingBlock, DefiniteContainingBlock}; use crate::{ContainingBlock, DefiniteContainingBlock};
use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; 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 // FIXME: implement https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
available_size available_size
} else { } else {
shrink_to_fit( self.absolutely_positioned_box
&self.absolutely_positioned_box.contents.inline_content_sizes, .contents
available_size, .content_sizes
) .shrink_to_fit(available_size)
} }
}); });

View file

@ -38,6 +38,13 @@ impl ContentSizesRequest {
Self::None => None, 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)] #[derive(Clone, Debug)]
@ -74,69 +81,72 @@ impl ContentSizes {
} }
} }
/// https://dbaron.org/css/intrinsic/#outer-intrinsic /// Optional min/max-content for storage in the box tree
pub(crate) fn outer_inline_content_sizes( #[derive(Debug)]
style: &ComputedValues, pub(crate) enum BoxContentSizes {
inner_content_sizes: &Option<ContentSizes>, NoneWereRequested, // … during box construction
) -> ContentSizes { Inline(ContentSizes),
let (mut outer, percentages) =
outer_inline_content_sizes_and_percentages(style, inner_content_sizes);
outer.adjust_for_pbm_percentages(percentages);
outer
} }
pub(crate) fn outer_inline_content_sizes_and_percentages( impl BoxContentSizes {
style: &ComputedValues, fn expect_inline(&self) -> &ContentSizes {
inner_content_sizes: &Option<ContentSizes>, match self {
) -> (ContentSizes, Percentage) { Self::NoneWereRequested => panic!("Accessing content size that was not requested"),
// FIXME: account for 'min-width', 'max-width', 'box-sizing' Self::Inline(s) => s,
}
}
let inline_size = style.box_size().inline; /// https://dbaron.org/css/intrinsic/#outer-intrinsic
// Percentages for 'width' are treated as 'auto' pub fn outer_inline(&self, style: &ComputedValues) -> ContentSizes {
let inline_size = inline_size.map(|lp| lp.as_length()); let (mut outer, percentages) = self.outer_inline_and_percentages(style);
// The (inner) min/max-content are only used for 'auto' outer.adjust_for_pbm_percentages(percentages);
let mut outer = match inline_size.non_auto().flatten() { outer
None => expect(inner_content_sizes).clone(), }
Some(length) => ContentSizes {
min_content: length,
max_content: length,
},
};
let mut pbm_lengths = Length::zero(); pub(crate) fn outer_inline_and_percentages(
let mut pbm_percentages = Percentage::zero(); &self,
let padding = style.padding(); style: &ComputedValues,
let border = style.border_width(); ) -> (ContentSizes, Percentage) {
let margin = style.margin(); // FIXME: account for 'min-width', 'max-width', 'box-sizing'
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; let inline_size = style.box_size().inline;
outer.max_content += pbm_lengths; // 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) let mut pbm_lengths = Length::zero();
} let mut pbm_percentages = Percentage::zero();
let padding = style.padding();
/// https://drafts.csswg.org/css2/visudet.html#shrink-to-fit-float let border = style.border_width();
pub(crate) fn shrink_to_fit( let margin = style.margin();
content_sizes: &Option<ContentSizes>, pbm_lengths += border.inline_sum();
available_size: Length, let mut add = |x: LengthPercentage| {
) -> Length { pbm_lengths += x.length_component();
let content_sizes = expect(content_sizes); pbm_percentages += x.percentage_component();
available_size };
.max(content_sizes.min_content) add(padding.inline_start);
.min(content_sizes.max_content) add(padding.inline_end);
} margin.inline_start.non_auto().map(&mut add);
margin.inline_end.non_auto().map(&mut add);
fn expect(content_sizes: &Option<ContentSizes>) -> &ContentSizes {
content_sizes outer.min_content += pbm_lengths;
.as_ref() outer.max_content += pbm_lengths;
.expect("Accessing content size that was not requested")
(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)
}
} }