Compute content sizes lazily in layout 2020

This commit is contained in:
Anthony Ramine 2020-06-18 14:11:02 +02:00
parent ba5568a0a6
commit 235df94f2e
11 changed files with 176 additions and 247 deletions

View file

@ -12,7 +12,6 @@ use crate::element_data::LayoutBox;
use crate::formatting_contexts::IndependentFormattingContext; use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::Tag; use crate::fragments::Tag;
use crate::positioned::AbsolutelyPositionedBox; use crate::positioned::AbsolutelyPositionedBox;
use crate::sizing::{BoxContentSizes, ContentSizes, ContentSizesRequest};
use crate::style_ext::DisplayGeneratingBox; use crate::style_ext::DisplayGeneratingBox;
use rayon::iter::{IntoParallelIterator, ParallelIterator}; use rayon::iter::{IntoParallelIterator, ParallelIterator};
use std::borrow::Cow; use std::borrow::Cow;
@ -23,9 +22,8 @@ impl FlexContainer {
context: &LayoutContext, context: &LayoutContext,
info: &NodeAndStyleInfo<impl NodeExt<'dom>>, info: &NodeAndStyleInfo<impl NodeExt<'dom>>,
contents: NonReplacedContents, contents: NonReplacedContents,
content_sizes: ContentSizesRequest,
propagated_text_decoration_line: TextDecorationLine, propagated_text_decoration_line: TextDecorationLine,
) -> (Self, BoxContentSizes) { ) -> Self {
let text_decoration_line = let text_decoration_line =
propagated_text_decoration_line | info.style.clone_text_decoration_line(); propagated_text_decoration_line | info.style.clone_text_decoration_line();
let mut builder = FlexContainerBuilder { let mut builder = FlexContainerBuilder {
@ -37,11 +35,7 @@ impl FlexContainer {
has_text_runs: false, has_text_runs: false,
}; };
contents.traverse(context, info, &mut builder); contents.traverse(context, info, &mut builder);
let content_sizes = content_sizes.compute(|| { builder.finish()
// FIXME
ContentSizes::zero()
});
(builder.finish(), content_sizes)
} }
} }
@ -152,7 +146,6 @@ where
.map(|job| match job { .map(|job| match job {
FlexLevelJob::TextRuns(runs) => ArcRefCell::new(FlexLevelBox::FlexItem( FlexLevelJob::TextRuns(runs) => ArcRefCell::new(FlexLevelBox::FlexItem(
IndependentFormattingContext::construct_for_text_runs( IndependentFormattingContext::construct_for_text_runs(
self.context,
&self &self
.info .info
.new_replacing_style(anonymous_style.clone().unwrap()), .new_replacing_style(anonymous_style.clone().unwrap()),
@ -161,7 +154,6 @@ where
text: run.text.into(), text: run.text.into(),
parent_style: run.info.style, parent_style: run.info.style,
}), }),
ContentSizesRequest::None, // FIXME: request sizes when we start using them
self.text_decoration_line, self.text_decoration_line,
), ),
)), )),
@ -191,7 +183,6 @@ where
&info, &info,
display_inside, display_inside,
contents, contents,
ContentSizesRequest::None, // FIXME: request sizes when we start using them
self.text_decoration_line, self.text_decoration_line,
), ),
)) ))

View file

@ -5,6 +5,7 @@
use crate::cell::ArcRefCell; use crate::cell::ArcRefCell;
use crate::formatting_contexts::IndependentFormattingContext; use crate::formatting_contexts::IndependentFormattingContext;
use crate::positioned::AbsolutelyPositionedBox; use crate::positioned::AbsolutelyPositionedBox;
use crate::sizing::ContentSizes;
mod construct; mod construct;
mod layout; mod layout;
@ -19,3 +20,9 @@ pub(crate) enum FlexLevelBox {
FlexItem(IndependentFormattingContext), FlexItem(IndependentFormattingContext),
OutOfFlowAbsolutelyPositionedBox(ArcRefCell<AbsolutelyPositionedBox>), OutOfFlowAbsolutelyPositionedBox(ArcRefCell<AbsolutelyPositionedBox>),
} }
impl FlexContainer {
pub fn inline_content_sizes(&self) -> ContentSizes {
unimplemented!()
}
}

View file

@ -14,14 +14,12 @@ use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
use crate::formatting_contexts::IndependentFormattingContext; use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::Tag; use crate::fragments::Tag;
use crate::positioned::AbsolutelyPositionedBox; use crate::positioned::AbsolutelyPositionedBox;
use crate::sizing::{self, BoxContentSizes, ContentSizes, ContentSizesRequest}; use crate::style_ext::{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;
use servo_arc::Arc; use servo_arc::Arc;
use std::borrow::Cow; use std::borrow::Cow;
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
use style::logical_geometry::WritingMode;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::selector_parser::PseudoElement; use style::selector_parser::PseudoElement;
use style::values::specified::text::TextDecorationLine; use style::values::specified::text::TextDecorationLine;
@ -31,34 +29,24 @@ impl BlockFormattingContext {
context: &LayoutContext, context: &LayoutContext,
info: &NodeAndStyleInfo<Node>, info: &NodeAndStyleInfo<Node>,
contents: NonReplacedContents, contents: NonReplacedContents,
content_sizes: ContentSizesRequest,
propagated_text_decoration_line: TextDecorationLine, propagated_text_decoration_line: TextDecorationLine,
) -> (Self, BoxContentSizes) ) -> Self
where where
Node: NodeExt<'dom>, Node: NodeExt<'dom>,
{ {
let (contents, contains_floats, inline_content_sizes) = BlockContainer::construct( let (contents, contains_floats) =
context, BlockContainer::construct(context, info, contents, propagated_text_decoration_line);
info,
contents,
content_sizes,
propagated_text_decoration_line,
);
// FIXME: add contribution to `inline_content_sizes` of floats in this formatting context
// https://dbaron.org/css/intrinsic/#intrinsic
let bfc = Self { let bfc = Self {
contents, contents,
contains_floats: contains_floats == ContainsFloats::Yes, contains_floats: contains_floats == ContainsFloats::Yes,
}; };
(bfc, inline_content_sizes) bfc
} }
pub fn construct_for_text_runs<'dom>( pub fn construct_for_text_runs<'dom>(
context: &LayoutContext,
runs: impl Iterator<Item = TextRun>, runs: impl Iterator<Item = TextRun>,
content_sizes: ContentSizesRequest,
text_decoration_line: TextDecorationLine, text_decoration_line: TextDecorationLine,
) -> (Self, BoxContentSizes) { ) -> Self {
// FIXME: do white space collapsing // FIXME: do white space collapsing
let inline_level_boxes = runs let inline_level_boxes = runs
.map(|run| ArcRefCell::new(InlineLevelBox::TextRun(run))) .map(|run| ArcRefCell::new(InlineLevelBox::TextRun(run)))
@ -68,18 +56,12 @@ impl BlockFormattingContext {
inline_level_boxes, inline_level_boxes,
text_decoration_line, text_decoration_line,
}; };
// FIXME: this is the wrong writing mode
// but we plan to remove eager content size computation.
let not_actually_containing_block_writing_mode = WritingMode::empty();
let content_sizes = content_sizes.compute(|| {
ifc.inline_content_sizes(context, not_actually_containing_block_writing_mode)
});
let contents = BlockContainer::InlineFormattingContext(ifc); let contents = BlockContainer::InlineFormattingContext(ifc);
let bfc = Self { let bfc = Self {
contents, contents,
contains_floats: false, contains_floats: false,
}; };
(bfc, content_sizes) bfc
} }
} }
@ -181,9 +163,8 @@ impl BlockContainer {
context: &LayoutContext, context: &LayoutContext,
info: &NodeAndStyleInfo<Node>, info: &NodeAndStyleInfo<Node>,
contents: NonReplacedContents, contents: NonReplacedContents,
content_sizes: ContentSizesRequest,
propagated_text_decoration_line: TextDecorationLine, propagated_text_decoration_line: TextDecorationLine,
) -> (BlockContainer, ContainsFloats, BoxContentSizes) ) -> (BlockContainer, ContainsFloats)
where where
Node: NodeExt<'dom>, Node: NodeExt<'dom>,
{ {
@ -209,35 +190,22 @@ impl BlockContainer {
.is_empty() .is_empty()
{ {
if builder.block_level_boxes.is_empty() { if builder.block_level_boxes.is_empty() {
// FIXME: this is the wrong writing mode
// but we plan to remove eager content size computation.
let not_actually_containing_block_writing_mode = info.style.writing_mode;
let content_sizes = content_sizes.compute(|| {
builder
.ongoing_inline_formatting_context
.inline_content_sizes(context, not_actually_containing_block_writing_mode)
});
let container = BlockContainer::InlineFormattingContext( let container = BlockContainer::InlineFormattingContext(
builder.ongoing_inline_formatting_context, builder.ongoing_inline_formatting_context,
); );
return (container, builder.contains_floats, content_sizes); return (container, builder.contains_floats);
} }
builder.end_ongoing_inline_formatting_context(); builder.end_ongoing_inline_formatting_context();
} }
struct Accumulator { struct Accumulator {
contains_floats: ContainsFloats, contains_floats: ContainsFloats,
outer_content_sizes_of_children: ContentSizes,
} }
let mut acc = Accumulator { let mut acc = Accumulator {
contains_floats: builder.contains_floats, contains_floats: builder.contains_floats,
outer_content_sizes_of_children: ContentSizes::zero(),
}; };
let mapfold = |acc: &mut Accumulator, creator: BlockLevelJob<'dom, _>| { let mapfold = |acc: &mut Accumulator, creator: BlockLevelJob<'dom, _>| {
let (block_level_box, box_contains_floats) = creator.finish( let (block_level_box, box_contains_floats) = creator.finish(context);
context,
content_sizes.if_requests_inline(|| &mut acc.outer_content_sizes_of_children),
);
acc.contains_floats |= box_contains_floats; acc.contains_floats |= box_contains_floats;
block_level_box block_level_box
}; };
@ -250,14 +218,9 @@ impl BlockContainer {
mapfold, mapfold,
|| Accumulator { || Accumulator {
contains_floats: ContainsFloats::No, contains_floats: ContainsFloats::No,
outer_content_sizes_of_children: ContentSizes::zero(),
}, },
|left, right| { |left, right| {
left.contains_floats |= right.contains_floats; left.contains_floats |= right.contains_floats;
if content_sizes.requests_inline() {
left.outer_content_sizes_of_children
.max_assign(&right.outer_content_sizes_of_children)
}
}, },
) )
.collect() .collect()
@ -270,12 +233,8 @@ impl BlockContainer {
}; };
let container = BlockContainer::BlockLevelBoxes(block_level_boxes); let container = BlockContainer::BlockLevelBoxes(block_level_boxes);
let Accumulator { let Accumulator { contains_floats } = acc;
contains_floats, (container, contains_floats)
outer_content_sizes_of_children,
} = acc;
let content_sizes = content_sizes.compute(|| outer_content_sizes_of_children);
(container, contains_floats, content_sizes)
} }
} }
@ -439,7 +398,6 @@ where
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents, contents: Contents,
) -> ArcRefCell<InlineLevelBox> { ) -> ArcRefCell<InlineLevelBox> {
let style = &info.style;
let box_ = if display_inside == DisplayInside::Flow && !contents.is_replaced() { let box_ = if display_inside == DisplayInside::Flow && !contents.is_replaced() {
// We found un inline box. // We found un inline box.
// Whatever happened before, all we need to do before recurring // Whatever happened before, all we need to do before recurring
@ -464,14 +422,12 @@ where
inline_box.last_fragment = true; inline_box.last_fragment = true;
ArcRefCell::new(InlineLevelBox::InlineBox(inline_box)) ArcRefCell::new(InlineLevelBox::InlineBox(inline_box))
} else { } else {
let content_sizes = ContentSizesRequest::inline_if(!style.inline_size_is_length());
ArcRefCell::new(InlineLevelBox::Atomic( ArcRefCell::new(InlineLevelBox::Atomic(
IndependentFormattingContext::construct( IndependentFormattingContext::construct(
self.context, self.context,
info, info,
display_inside, display_inside,
contents, contents,
content_sizes,
// Text decorations are not propagated to atomic inline-level descendants. // Text decorations are not propagated to atomic inline-level descendants.
TextDecorationLine::NONE, TextDecorationLine::NONE,
), ),
@ -681,32 +637,11 @@ impl<'dom, Node> BlockLevelJob<'dom, Node>
where where
Node: NodeExt<'dom>, Node: NodeExt<'dom>,
{ {
fn finish( fn finish(self, context: &LayoutContext) -> (ArcRefCell<BlockLevelBox>, ContainsFloats) {
self,
context: &LayoutContext,
max_assign_in_flow_outer_content_sizes_to: Option<&mut ContentSizes>,
) -> (ArcRefCell<BlockLevelBox>, ContainsFloats) {
let info = &self.info; let info = &self.info;
// FIXME: this is the wrong writing mode
// but we plan to remove eager content size computation.
let not_actually_containing_block_writing_mode = info.style.writing_mode;
let (block_level_box, contains_floats) = match self.kind { let (block_level_box, contains_floats) = match self.kind {
BlockLevelCreator::SameFormattingContextBlock(contents) => { BlockLevelCreator::SameFormattingContextBlock(contents) => {
let (contents, contains_floats, box_content_sizes) = contents.finish( let (contents, contains_floats) = contents.finish(context, info);
context,
info,
ContentSizesRequest::inline_if(
max_assign_in_flow_outer_content_sizes_to.is_some() &&
!info.style.inline_size_is_length(),
),
);
if let Some(to) = max_assign_in_flow_outer_content_sizes_to {
to.max_assign(&sizing::outer_inline(
&info.style,
not_actually_containing_block_writing_mode,
|| box_content_sizes.expect_inline().clone(),
))
}
let block_level_box = ArcRefCell::new(BlockLevelBox::SameFormattingContextBlock { let block_level_box = ArcRefCell::new(BlockLevelBox::SameFormattingContextBlock {
tag: Tag::from_node_and_style_info(info), tag: Tag::from_node_and_style_info(info),
contents, contents,
@ -719,25 +654,13 @@ where
contents, contents,
propagated_text_decoration_line, propagated_text_decoration_line,
} => { } => {
let content_sizes = ContentSizesRequest::inline_if(
max_assign_in_flow_outer_content_sizes_to.is_some() &&
!info.style.inline_size_is_length(),
);
let context = IndependentFormattingContext::construct( let context = IndependentFormattingContext::construct(
context, context,
info, info,
display_inside, display_inside,
contents, contents,
content_sizes,
propagated_text_decoration_line, propagated_text_decoration_line,
); );
if let Some(to) = max_assign_in_flow_outer_content_sizes_to {
to.max_assign(&sizing::outer_inline(
&context.style(),
not_actually_containing_block_writing_mode,
|| context.content_sizes(),
))
}
( (
ArcRefCell::new(BlockLevelBox::Independent(context)), ArcRefCell::new(BlockLevelBox::Independent(context)),
ContainsFloats::No, ContainsFloats::No,
@ -775,35 +698,21 @@ impl IntermediateBlockContainer {
self, self,
context: &LayoutContext, context: &LayoutContext,
info: &NodeAndStyleInfo<Node>, info: &NodeAndStyleInfo<Node>,
content_sizes: ContentSizesRequest, ) -> (BlockContainer, ContainsFloats)
) -> (BlockContainer, ContainsFloats, BoxContentSizes)
where where
Node: NodeExt<'dom>, Node: NodeExt<'dom>,
{ {
match self { match self {
IntermediateBlockContainer::Deferred(contents, propagated_text_decoration_line) => { IntermediateBlockContainer::Deferred(contents, propagated_text_decoration_line) => {
BlockContainer::construct( BlockContainer::construct(context, info, contents, propagated_text_decoration_line)
context,
info,
contents,
content_sizes,
propagated_text_decoration_line,
)
}, },
IntermediateBlockContainer::InlineFormattingContext(ifc) => { IntermediateBlockContainer::InlineFormattingContext(ifc) => {
// FIXME: this is the wrong writing mode
// but we plan to remove eager content size computation.
let not_actually_containing_block_writing_mode = info.style.writing_mode;
let content_sizes = content_sizes.compute(|| {
ifc.inline_content_sizes(context, not_actually_containing_block_writing_mode)
});
// 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,
content_sizes,
) )
}, },
} }

View file

@ -5,8 +5,7 @@
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::dom_traversal::{Contents, NodeAndStyleInfo, NodeExt}; use crate::dom_traversal::{Contents, NodeAndStyleInfo, NodeExt};
use crate::formatting_contexts::IndependentFormattingContext; use crate::formatting_contexts::IndependentFormattingContext;
use crate::sizing::ContentSizesRequest; use crate::style_ext::DisplayInside;
use crate::style_ext::{ComputedValuesExt, DisplayInside};
use style::values::specified::text::TextDecorationLine; use style::values::specified::text::TextDecorationLine;
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
@ -32,14 +31,12 @@ impl FloatBox {
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents, contents: Contents,
) -> Self { ) -> Self {
let content_sizes = ContentSizesRequest::inline_if(!info.style.inline_size_is_length());
Self { Self {
contents: IndependentFormattingContext::construct( contents: IndependentFormattingContext::construct(
context, context,
info, info,
display_inside, display_inside,
contents, contents,
content_sizes,
// Text decorations are not propagated to any out-of-flow descendants // Text decorations are not propagated to any out-of-flow descendants
TextDecorationLine::NONE, TextDecorationLine::NONE,
), ),

View file

@ -16,7 +16,7 @@ use crate::positioned::{
relative_adjustement, AbsolutelyPositionedBox, HoistedAbsolutelyPositionedBox, relative_adjustement, AbsolutelyPositionedBox, HoistedAbsolutelyPositionedBox,
PositioningContext, PositioningContext,
}; };
use crate::sizing::{self, ContentSizes}; use crate::sizing::ContentSizes;
use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside}; use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside};
use crate::ContainingBlock; use crate::ContainingBlock;
use app_units::Au; use app_units::Au;
@ -200,10 +200,9 @@ impl InlineFormattingContext {
} }
}, },
InlineLevelBox::Atomic(atomic) => { InlineLevelBox::Atomic(atomic) => {
let (outer, pc) = sizing::outer_inline_and_percentages( let (outer, pc) = atomic.outer_inline_and_percentages(
&atomic.style(), self.layout_context,
self.containing_block_writing_mode, self.containing_block_writing_mode,
|| atomic.content_sizes(),
); );
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;
@ -595,7 +594,9 @@ fn layout_atomic(
// https://drafts.csswg.org/css2/visudet.html#inlineblock-width // https://drafts.csswg.org/css2/visudet.html#inlineblock-width
let tentative_inline_size = box_size.inline.auto_is(|| { let tentative_inline_size = box_size.inline.auto_is(|| {
let available_size = ifc.containing_block.inline_size - pbm_sums.inline_sum(); let available_size = ifc.containing_block.inline_size - pbm_sums.inline_sum();
non_replaced.content_sizes.shrink_to_fit(available_size) non_replaced
.inline_content_sizes(layout_context)
.shrink_to_fit(available_size)
}); });
// https://drafts.csswg.org/css2/visudet.html#min-max-widths // https://drafts.csswg.org/css2/visudet.html#min-max-widths

View file

@ -18,11 +18,13 @@ use crate::fragments::{
use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
use crate::replaced::ReplacedContent; use crate::replaced::ReplacedContent;
use crate::sizing::{self, ContentSizes};
use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin}; use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin};
use crate::ContainingBlock; use crate::ContainingBlock;
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
use rayon_croissant::ParallelIteratorExt; use rayon_croissant::ParallelIteratorExt;
use servo_arc::Arc; use servo_arc::Arc;
use style::logical_geometry::WritingMode;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::{Length, LengthOrAuto}; use style::values::computed::{Length, LengthOrAuto};
use style::Zero; use style::Zero;
@ -132,6 +134,29 @@ impl BlockContainer {
), ),
} }
} }
pub(super) fn inline_content_sizes(
&self,
layout_context: &LayoutContext,
containing_block_writing_mode: WritingMode,
) -> ContentSizes {
match &self {
Self::BlockLevelBoxes(boxes) => {
let mut content_sizes = ContentSizes::zero();
for box_ in boxes {
content_sizes.max_assign(
&box_
.borrow_mut()
.inline_content_sizes(layout_context, containing_block_writing_mode),
);
}
content_sizes
},
Self::InlineFormattingContext(context) => {
context.inline_content_sizes(layout_context, containing_block_writing_mode)
},
}
}
} }
fn layout_block_level_children( fn layout_block_level_children(
@ -350,6 +375,28 @@ impl BlockLevelBox {
}, },
} }
} }
fn inline_content_sizes(
&mut self,
layout_context: &LayoutContext,
containing_block_writing_mode: WritingMode,
) -> ContentSizes {
match self {
Self::SameFormattingContextBlock {
style, contents, ..
} => sizing::outer_inline(style, containing_block_writing_mode, || {
contents.inline_content_sizes(layout_context, style.writing_mode)
}),
Self::Independent(independent) => {
independent.outer_inline(layout_context, containing_block_writing_mode)
},
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(_) => ContentSizes::zero(),
BlockLevelBox::OutOfFlowFloatBox(_box_) => {
// TODO: Actually implement that.
ContentSizes::zero()
},
}
}
} }
enum NonReplacedContents<'a> { enum NonReplacedContents<'a> {

View file

@ -22,7 +22,6 @@ use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSize};
use crate::positioned::AbsolutelyPositionedBox; use crate::positioned::AbsolutelyPositionedBox;
use crate::positioned::PositioningContext; use crate::positioned::PositioningContext;
use crate::replaced::ReplacedContent; use crate::replaced::ReplacedContent;
use crate::sizing::ContentSizesRequest;
use crate::style_ext::ComputedValuesExt; use crate::style_ext::ComputedValuesExt;
use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside}; use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside};
use crate::wrapper::GetStyleAndLayoutData; use crate::wrapper::GetStyleAndLayoutData;
@ -291,7 +290,6 @@ fn construct_for_root_element<'dom>(
&info, &info,
display_inside, display_inside,
contents, contents,
ContentSizesRequest::None,
propagated_text_decoration_line, propagated_text_decoration_line,
)), )),
) )

View file

@ -9,13 +9,14 @@ use crate::flow::BlockFormattingContext;
use crate::fragments::{Fragment, Tag}; use crate::fragments::{Fragment, Tag};
use crate::positioned::PositioningContext; use crate::positioned::PositioningContext;
use crate::replaced::ReplacedContent; use crate::replaced::ReplacedContent;
use crate::sizing::{BoxContentSizes, ContentSizes, ContentSizesRequest}; use crate::sizing::{self, ContentSizes};
use crate::style_ext::DisplayInside; use crate::style_ext::DisplayInside;
use crate::ContainingBlock; use crate::ContainingBlock;
use servo_arc::Arc; use servo_arc::Arc;
use std::convert::TryInto; use std::convert::TryInto;
use style::logical_geometry::WritingMode;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::Length; use style::values::computed::{Length, Percentage};
use style::values::specified::text::TextDecorationLine; use style::values::specified::text::TextDecorationLine;
/// https://drafts.csswg.org/css-display/#independent-formatting-context /// https://drafts.csswg.org/css-display/#independent-formatting-context
@ -31,7 +32,7 @@ pub(crate) struct NonReplacedFormattingContext {
#[serde(skip_serializing)] #[serde(skip_serializing)]
pub style: Arc<ComputedValues>, pub style: Arc<ComputedValues>,
/// If it was requested during construction /// If it was requested during construction
pub content_sizes: BoxContentSizes, pub content_sizes: Option<ContentSizes>,
pub contents: NonReplacedFormattingContextContents, pub contents: NonReplacedFormattingContextContents,
} }
@ -65,42 +66,37 @@ impl IndependentFormattingContext {
info: &NodeAndStyleInfo<impl NodeExt<'dom>>, info: &NodeAndStyleInfo<impl NodeExt<'dom>>,
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents, contents: Contents,
content_sizes: ContentSizesRequest,
propagated_text_decoration_line: TextDecorationLine, propagated_text_decoration_line: TextDecorationLine,
) -> Self { ) -> Self {
match contents.try_into() { match contents.try_into() {
Ok(non_replaced) => match display_inside { Ok(non_replaced) => {
let contents = match display_inside {
DisplayInside::Flow | DisplayInside::FlowRoot => { DisplayInside::Flow | DisplayInside::FlowRoot => {
let (bfc, content_sizes) = BlockFormattingContext::construct( NonReplacedFormattingContextContents::Flow(
BlockFormattingContext::construct(
context, context,
info, info,
non_replaced, non_replaced,
content_sizes,
propagated_text_decoration_line, propagated_text_decoration_line,
); ),
Self::NonReplaced(NonReplacedFormattingContext { )
tag: Tag::from_node_and_style_info(info),
style: Arc::clone(&info.style),
content_sizes,
contents: NonReplacedFormattingContextContents::Flow(bfc),
})
}, },
DisplayInside::Flex => { DisplayInside::Flex => {
let (fc, content_sizes) = FlexContainer::construct( NonReplacedFormattingContextContents::Flex(FlexContainer::construct(
context, context,
info, info,
non_replaced, non_replaced,
content_sizes,
propagated_text_decoration_line, propagated_text_decoration_line,
); ))
},
};
Self::NonReplaced(NonReplacedFormattingContext { Self::NonReplaced(NonReplacedFormattingContext {
tag: Tag::from_node_and_style_info(info), tag: Tag::from_node_and_style_info(info),
style: Arc::clone(&info.style), style: Arc::clone(&info.style),
content_sizes, content_sizes: None,
contents: NonReplacedFormattingContextContents::Flex(fc), contents,
}) })
}, },
},
Err(contents) => Self::Replaced(ReplacedFormattingContext { Err(contents) => Self::Replaced(ReplacedFormattingContext {
tag: Tag::from_node_and_style_info(info), tag: Tag::from_node_and_style_info(info),
style: Arc::clone(&info.style), style: Arc::clone(&info.style),
@ -110,22 +106,16 @@ impl IndependentFormattingContext {
} }
pub fn construct_for_text_runs<'dom>( pub fn construct_for_text_runs<'dom>(
context: &LayoutContext,
info: &NodeAndStyleInfo<impl NodeExt<'dom>>, info: &NodeAndStyleInfo<impl NodeExt<'dom>>,
runs: impl Iterator<Item = crate::flow::inline::TextRun>, runs: impl Iterator<Item = crate::flow::inline::TextRun>,
content_sizes: ContentSizesRequest,
propagated_text_decoration_line: TextDecorationLine, propagated_text_decoration_line: TextDecorationLine,
) -> Self { ) -> Self {
let (bfc, content_sizes) = BlockFormattingContext::construct_for_text_runs( let bfc =
context, BlockFormattingContext::construct_for_text_runs(runs, propagated_text_decoration_line);
runs,
content_sizes,
propagated_text_decoration_line,
);
Self::NonReplaced(NonReplacedFormattingContext { Self::NonReplaced(NonReplacedFormattingContext {
tag: Tag::from_node_and_style_info(info), tag: Tag::from_node_and_style_info(info),
style: Arc::clone(&info.style), style: Arc::clone(&info.style),
content_sizes, content_sizes: None,
contents: NonReplacedFormattingContextContents::Flow(bfc), contents: NonReplacedFormattingContextContents::Flow(bfc),
}) })
} }
@ -144,10 +134,40 @@ impl IndependentFormattingContext {
} }
} }
pub fn content_sizes(&self) -> ContentSizes { pub fn outer_inline(
&mut self,
layout_context: &LayoutContext,
containing_block_writing_mode: WritingMode,
) -> ContentSizes {
let (mut outer, percentages) =
self.outer_inline_and_percentages(layout_context, containing_block_writing_mode);
outer.adjust_for_pbm_percentages(percentages);
outer
}
pub fn outer_inline_and_percentages(
&mut self,
layout_context: &LayoutContext,
containing_block_writing_mode: WritingMode,
) -> (ContentSizes, Percentage) {
match self { match self {
Self::NonReplaced(inner) => inner.content_sizes.expect_inline().clone(), Self::NonReplaced(non_replaced) => {
Self::Replaced(inner) => inner.contents.inline_content_sizes(&inner.style), 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, || {
content_sizes
.get_or_insert_with(|| {
contents.inline_content_sizes(layout_context, style.writing_mode)
})
.clone()
})
},
Self::Replaced(replaced) => sizing::outer_inline_and_percentages(
&replaced.style,
containing_block_writing_mode,
|| replaced.contents.inline_content_sizes(&replaced.style),
),
} }
} }
} }
@ -175,4 +195,27 @@ impl NonReplacedFormattingContext {
), ),
} }
} }
pub fn inline_content_sizes(&mut self, layout_context: &LayoutContext) -> ContentSizes {
let writing_mode = self.style.writing_mode;
let contents = &self.contents;
self.content_sizes
.get_or_insert_with(|| contents.inline_content_sizes(layout_context, writing_mode))
.clone()
}
}
impl NonReplacedFormattingContextContents {
pub fn inline_content_sizes(
&self,
layout_context: &LayoutContext,
containing_block_writing_mode: WritingMode,
) -> ContentSizes {
match self {
Self::Flow(inner) => inner
.contents
.inline_content_sizes(layout_context, containing_block_writing_mode),
Self::Flex(inner) => inner.inline_content_sizes(),
}
}
} }

View file

@ -9,7 +9,6 @@ use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::{BoxFragment, CollapsedBlockMargins, Fragment}; use crate::fragments::{BoxFragment, CollapsedBlockMargins, Fragment};
use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::geom::{LengthOrAuto, LengthPercentageOrAuto}; use crate::geom::{LengthOrAuto, LengthPercentageOrAuto};
use crate::sizing::ContentSizesRequest;
use crate::style_ext::{ComputedValuesExt, DisplayInside}; use crate::style_ext::{ComputedValuesExt, DisplayInside};
use crate::{ContainingBlock, DefiniteContainingBlock}; use crate::{ContainingBlock, DefiniteContainingBlock};
use rayon::iter::{IntoParallelRefMutIterator, ParallelExtend}; use rayon::iter::{IntoParallelRefMutIterator, ParallelExtend};
@ -74,22 +73,12 @@ impl AbsolutelyPositionedBox {
display_inside: DisplayInside, display_inside: DisplayInside,
contents: Contents, contents: Contents,
) -> Self { ) -> Self {
// "Shrink-to-fit" in https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width
let content_sizes = ContentSizesRequest::inline_if(
// If inline-size is non-auto, that value is used without shrink-to-fit
!node_info.style.inline_size_is_length() &&
// If it is, then the only case where shrink-to-fit is *not* used is
// if both offsets are non-auto, leaving inline-size as the only variable
// in the constraint equation.
!node_info.style.inline_box_offsets_are_both_non_auto(),
);
Self { Self {
context: IndependentFormattingContext::construct( context: IndependentFormattingContext::construct(
context, context,
node_info, node_info,
display_inside, display_inside,
contents, contents,
content_sizes,
// Text decorations are not propagated to any out-of-flow descendants. // Text decorations are not propagated to any out-of-flow descendants.
TextDecorationLine::NONE, TextDecorationLine::NONE,
), ),
@ -472,7 +461,9 @@ impl HoistedAbsolutelyPositionedBox {
}; };
let available_size = let available_size =
cbis - anchor - pbm.padding_border_sums.inline - margin.inline_sum(); cbis - anchor - pbm.padding_border_sums.inline - margin.inline_sum();
non_replaced.content_sizes.shrink_to_fit(available_size) non_replaced
.inline_content_sizes(layout_context)
.shrink_to_fit(available_size)
}); });
let containing_block_for_children = ContainingBlock { let containing_block_for_children = ContainingBlock {

View file

@ -11,44 +11,6 @@ use style::properties::ComputedValues;
use style::values::computed::{Length, LengthPercentage, Percentage}; use style::values::computed::{Length, LengthPercentage, Percentage};
use style::Zero; use style::Zero;
/// Which min/max-content values should be computed during box construction
#[derive(Clone, Copy, Debug)]
pub(crate) enum ContentSizesRequest {
Inline,
None,
}
impl ContentSizesRequest {
pub fn inline_if(condition: bool) -> Self {
if condition {
Self::Inline
} else {
Self::None
}
}
pub fn requests_inline(self) -> bool {
match self {
Self::Inline => true,
Self::None => false,
}
}
pub fn if_requests_inline<T>(self, f: impl FnOnce() -> T) -> Option<T> {
match self {
Self::Inline => Some(f()),
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, Serialize)] #[derive(Clone, Debug, Serialize)]
pub(crate) struct ContentSizes { pub(crate) struct ContentSizes {
pub min_content: Length, pub min_content: Length,
@ -90,27 +52,10 @@ impl ContentSizes {
} }
} }
/// Optional min/max-content for storage in the box tree impl ContentSizes {
#[derive(Debug, Serialize)]
pub(crate) enum BoxContentSizes {
NoneWereRequested, // … during box construction
Inline(ContentSizes),
}
impl BoxContentSizes {
pub fn expect_inline(&self) -> &ContentSizes {
match self {
Self::NoneWereRequested => panic!("Accessing content size that was not requested"),
Self::Inline(s) => s,
}
}
/// https://drafts.csswg.org/css2/visudet.html#shrink-to-fit-float /// https://drafts.csswg.org/css2/visudet.html#shrink-to-fit-float
pub(crate) fn shrink_to_fit(&self, available_size: Length) -> Length { pub fn shrink_to_fit(&self, available_size: Length) -> Length {
let inline = self.expect_inline(); available_size.max(self.min_content).min(self.max_content)
available_size
.max(inline.min_content)
.min(inline.max_content)
} }
} }

View file

@ -75,7 +75,7 @@ where
{ {
/// Resolves `auto` values by calling `f`. /// Resolves `auto` values by calling `f`.
#[inline] #[inline]
pub fn auto_is(&self, f: impl Fn() -> LengthPercentage) -> LengthPercentage { pub fn auto_is(&self, f: impl FnOnce() -> LengthPercentage) -> LengthPercentage {
match self { match self {
LengthPercentageOrAuto::LengthPercentage(length) => length.clone(), LengthPercentageOrAuto::LengthPercentage(length) => length.clone(),
LengthPercentageOrAuto::Auto => f(), LengthPercentageOrAuto::Auto => f(),