Auto merge of #26852 - servo:layout-2020-independent-kind, r=SimonSapin

Some more boring stuff to change how we compute content sizes
This commit is contained in:
bors-servo 2020-06-15 14:02:42 -04:00 committed by GitHub
commit 24cc72ba85
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 343 additions and 335 deletions

View file

@ -204,7 +204,7 @@ where
// https://drafts.csswg.org/css-flexbox/#order-modified-document-order // https://drafts.csswg.org/css-flexbox/#order-modified-document-order
children.sort_by_key(|child| match &*child.borrow() { children.sort_by_key(|child| match &*child.borrow() {
FlexLevelBox::FlexItem(item) => item.style.clone_order(), FlexLevelBox::FlexItem(item) => item.style().clone_order(),
// “Absolutely-positioned children of a flex container are treated // “Absolutely-positioned children of a flex container are treated
// as having order: 0 for the purpose of determining their painting order // as having order: 0 for the purpose of determining their painting order

View file

@ -14,7 +14,7 @@ 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::{BoxContentSizes, ContentSizes, ContentSizesRequest}; use crate::sizing::{self, 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;
@ -701,10 +701,11 @@ 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( to.max_assign(&sizing::outer_inline(
&box_content_sizes &info.style,
.outer_inline(&info.style, not_actually_containing_block_writing_mode), 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),
@ -722,7 +723,7 @@ where
max_assign_in_flow_outer_content_sizes_to.is_some() && max_assign_in_flow_outer_content_sizes_to.is_some() &&
!info.style.inline_size_is_length(), !info.style.inline_size_is_length(),
); );
let contents = IndependentFormattingContext::construct( let context = IndependentFormattingContext::construct(
context, context,
info, info,
display_inside, display_inside,
@ -731,15 +732,14 @@ where
propagated_text_decoration_line, propagated_text_decoration_line,
); );
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( to.max_assign(&sizing::outer_inline(
&contents.content_sizes.outer_inline( &context.style(),
&contents.style,
not_actually_containing_block_writing_mode, not_actually_containing_block_writing_mode,
), || context.content_sizes(),
) ))
} }
( (
ArcRefCell::new(BlockLevelBox::Independent(contents)), ArcRefCell::new(BlockLevelBox::Independent(context)),
ContainsFloats::No, ContainsFloats::No,
) )
}, },

View file

@ -16,7 +16,7 @@ use crate::positioned::{
relative_adjustement, AbsolutelyPositionedBox, HoistedAbsolutelyPositionedBox, relative_adjustement, AbsolutelyPositionedBox, HoistedAbsolutelyPositionedBox,
PositioningContext, PositioningContext,
}; };
use crate::sizing::ContentSizes; use crate::sizing::{self, 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;
@ -155,7 +155,7 @@ impl InlineFormattingContext {
impl Computation<'_> { impl Computation<'_> {
fn traverse(&mut self, inline_level_boxes: &[ArcRefCell<InlineLevelBox>]) { fn traverse(&mut self, inline_level_boxes: &[ArcRefCell<InlineLevelBox>]) {
for inline_level_box in inline_level_boxes { for inline_level_box in inline_level_boxes {
match &*inline_level_box.borrow() { match &mut *inline_level_box.borrow_mut() {
InlineLevelBox::InlineBox(inline_box) => { InlineLevelBox::InlineBox(inline_box) => {
let padding = let padding =
inline_box.style.padding(self.containing_block_writing_mode); inline_box.style.padding(self.containing_block_writing_mode);
@ -200,9 +200,10 @@ impl InlineFormattingContext {
} }
}, },
InlineLevelBox::Atomic(atomic) => { InlineLevelBox::Atomic(atomic) => {
let (outer, pc) = atomic.content_sizes.outer_inline_and_percentages( let (outer, pc) = sizing::outer_inline_and_percentages(
&atomic.style, &atomic.style(),
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;
@ -294,7 +295,7 @@ impl InlineFormattingContext {
InlineLevelBox::TextRun(run) => run.layout(layout_context, &mut ifc), InlineLevelBox::TextRun(run) => run.layout(layout_context, &mut ifc),
InlineLevelBox::Atomic(a) => layout_atomic(layout_context, &mut ifc, a), InlineLevelBox::Atomic(a) => layout_atomic(layout_context, &mut ifc, a),
InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
let style = AtomicRef::map(box_.borrow(), |box_| &box_.contents.style); let style = AtomicRef::map(box_.borrow(), |box_| box_.context.style());
let initial_start_corner = let initial_start_corner =
match Display::from(style.get_box().original_display) { match Display::from(style.get_box().original_display) {
Display::GeneratingBox(DisplayGeneratingBox::OutsideInside { Display::GeneratingBox(DisplayGeneratingBox::OutsideInside {
@ -544,7 +545,8 @@ fn layout_atomic(
ifc: &mut InlineFormattingContextState, ifc: &mut InlineFormattingContextState,
atomic: &mut IndependentFormattingContext, atomic: &mut IndependentFormattingContext,
) { ) {
let pbm = atomic.style.padding_border_margin(&ifc.containing_block); let style = atomic.style();
let pbm = style.padding_border_margin(&ifc.containing_block);
let margin = pbm.margin.auto_is(Length::zero); let margin = pbm.margin.auto_is(Length::zero);
let pbm_sums = &(&pbm.padding + &pbm.border) + &margin; let pbm_sums = &(&pbm.padding + &pbm.border) + &margin;
ifc.inline_position += pbm_sums.inline_start; ifc.inline_position += pbm_sums.inline_start;
@ -552,19 +554,24 @@ fn layout_atomic(
block: pbm_sums.block_start, block: pbm_sums.block_start,
inline: ifc.inline_position - ifc.current_nesting_level.inline_start, inline: ifc.inline_position - ifc.current_nesting_level.inline_start,
}; };
if atomic.style.clone_position().is_relative() { if style.clone_position().is_relative() {
start_corner += &relative_adjustement(&atomic.style, ifc.containing_block) start_corner += &relative_adjustement(&style, ifc.containing_block)
} }
let fragment = match atomic.as_replaced() { let fragment = match atomic {
Ok(replaced) => { IndependentFormattingContext::Replaced(replaced) => {
let size = let size = replaced.contents.used_size_as_if_inline_element(
replaced.used_size_as_if_inline_element(ifc.containing_block, &atomic.style, &pbm); ifc.containing_block,
let fragments = replaced.make_fragments(&atomic.style, size.clone()); &replaced.style,
&pbm,
);
let fragments = replaced
.contents
.make_fragments(&replaced.style, size.clone());
let content_rect = Rect { start_corner, size }; let content_rect = Rect { start_corner, size };
BoxFragment::new( BoxFragment::new(
atomic.tag, replaced.tag,
atomic.style.clone(), replaced.style.clone(),
fragments, fragments,
content_rect, content_rect,
pbm.padding, pbm.padding,
@ -573,12 +580,14 @@ fn layout_atomic(
CollapsedBlockMargins::zero(), CollapsedBlockMargins::zero(),
) )
}, },
Err(non_replaced) => { IndependentFormattingContext::NonReplaced(non_replaced) => {
let box_size = atomic.style.content_box_size(&ifc.containing_block, &pbm); let box_size = non_replaced
let max_box_size = atomic .style
.content_box_size(&ifc.containing_block, &pbm);
let max_box_size = non_replaced
.style .style
.content_max_box_size(&ifc.containing_block, &pbm); .content_max_box_size(&ifc.containing_block, &pbm);
let min_box_size = atomic let min_box_size = non_replaced
.style .style
.content_min_box_size(&ifc.containing_block, &pbm) .content_min_box_size(&ifc.containing_block, &pbm)
.auto_is(Length::zero); .auto_is(Length::zero);
@ -586,7 +595,7 @@ 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();
atomic.content_sizes.shrink_to_fit(available_size) non_replaced.content_sizes.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
@ -598,7 +607,7 @@ fn layout_atomic(
let containing_block_for_children = ContainingBlock { let containing_block_for_children = ContainingBlock {
inline_size, inline_size,
block_size: box_size.block, block_size: box_size.block,
style: &atomic.style, style: &non_replaced.style,
}; };
assert_eq!( assert_eq!(
ifc.containing_block.style.writing_mode, ifc.containing_block.style.writing_mode,
@ -634,8 +643,8 @@ fn layout_atomic(
}, },
}; };
BoxFragment::new( BoxFragment::new(
atomic.tag, non_replaced.tag,
atomic.style.clone(), non_replaced.style.clone(),
independent_layout.fragments, independent_layout.fragments,
content_rect, content_rect,
pbm.padding, pbm.padding,

View file

@ -8,7 +8,9 @@ use crate::cell::ArcRefCell;
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::flow::float::{FloatBox, FloatContext}; use crate::flow::float::{FloatBox, FloatContext};
use crate::flow::inline::InlineFormattingContext; use crate::flow::inline::InlineFormattingContext;
use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout, NonReplacedIFC}; use crate::formatting_contexts::{
IndependentFormattingContext, IndependentLayout, NonReplacedFormattingContext,
};
use crate::fragments::{ use crate::fragments::{
AbsoluteOrFixedPositionedFragment, AnonymousFragment, BoxFragment, CollapsedBlockMargins, AbsoluteOrFixedPositionedFragment, AnonymousFragment, BoxFragment, CollapsedBlockMargins,
CollapsedMargin, Fragment, Tag, CollapsedMargin, Fragment, Tag,
@ -288,33 +290,44 @@ impl BlockLevelBox {
) )
}, },
)), )),
BlockLevelBox::Independent(contents) => { BlockLevelBox::Independent(independent) => match independent {
IndependentFormattingContext::Replaced(replaced) => {
Fragment::Box(positioning_context.layout_maybe_position_relative_fragment( Fragment::Box(positioning_context.layout_maybe_position_relative_fragment(
layout_context, layout_context,
containing_block, containing_block,
&contents.style, &replaced.style,
|positioning_context| match contents.as_replaced() { |_positioning_context| {
Ok(replaced) => layout_in_flow_replaced_block_level( layout_in_flow_replaced_block_level(
containing_block, containing_block,
contents.tag, replaced.tag,
&contents.style, &replaced.style,
replaced, &replaced.contents,
), )
Err(non_replaced) => layout_in_flow_non_replaced_block_level( },
))
},
IndependentFormattingContext::NonReplaced(non_replaced) => {
Fragment::Box(positioning_context.layout_maybe_position_relative_fragment(
layout_context,
containing_block,
&non_replaced.style,
|positioning_context| {
layout_in_flow_non_replaced_block_level(
layout_context, layout_context,
positioning_context, positioning_context,
containing_block, containing_block,
contents.tag, non_replaced.tag,
&contents.style, &non_replaced.style,
NonReplacedContents::EstablishesAnIndependentFormattingContext( NonReplacedContents::EstablishesAnIndependentFormattingContext(
non_replaced, non_replaced,
), ),
tree_rank, tree_rank,
float_context, float_context,
), )
}, },
)) ))
}, },
},
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
let hoisted_box = AbsolutelyPositionedBox::to_hoisted( let hoisted_box = AbsolutelyPositionedBox::to_hoisted(
box_.clone(), box_.clone(),
@ -326,7 +339,7 @@ impl BlockLevelBox {
positioning_context.push(hoisted_box); positioning_context.push(hoisted_box);
Fragment::AbsoluteOrFixedPositioned(AbsoluteOrFixedPositionedFragment { Fragment::AbsoluteOrFixedPositioned(AbsoluteOrFixedPositionedFragment {
hoisted_fragment, hoisted_fragment,
position: box_.borrow().contents.style.clone_position(), position: box_.borrow().context.style().clone_position(),
}) })
}, },
BlockLevelBox::OutOfFlowFloatBox(_box_) => { BlockLevelBox::OutOfFlowFloatBox(_box_) => {
@ -341,7 +354,7 @@ impl BlockLevelBox {
enum NonReplacedContents<'a> { enum NonReplacedContents<'a> {
SameFormattingContextBlock(&'a BlockContainer), SameFormattingContextBlock(&'a BlockContainer),
EstablishesAnIndependentFormattingContext(NonReplacedIFC<'a>), EstablishesAnIndependentFormattingContext(&'a NonReplacedFormattingContext),
} }
/// https://drafts.csswg.org/css2/visudet.html#blockwidth /// https://drafts.csswg.org/css2/visudet.html#blockwidth

View file

@ -9,7 +9,7 @@ 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, ContentSizesRequest}; use crate::sizing::{BoxContentSizes, ContentSizes, 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;
@ -20,15 +20,36 @@ use style::values::specified::text::TextDecorationLine;
/// https://drafts.csswg.org/css-display/#independent-formatting-context /// https://drafts.csswg.org/css-display/#independent-formatting-context
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub(crate) struct IndependentFormattingContext { pub(crate) enum IndependentFormattingContext {
NonReplaced(NonReplacedFormattingContext),
Replaced(ReplacedFormattingContext),
}
#[derive(Debug, Serialize)]
pub(crate) struct NonReplacedFormattingContext {
pub tag: Tag, pub tag: Tag,
#[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: BoxContentSizes,
pub contents: NonReplacedFormattingContextContents,
}
contents: IndependentFormattingContextContents, #[derive(Debug, Serialize)]
pub(crate) struct ReplacedFormattingContext {
pub tag: Tag,
#[serde(skip_serializing)]
pub style: Arc<ComputedValues>,
pub contents: ReplacedContent,
}
// Private so that code outside of this module cannot match variants.
// It should got through methods instead.
#[derive(Debug, Serialize)]
pub(crate) enum NonReplacedFormattingContextContents {
Flow(BlockFormattingContext),
Flex(FlexContainer),
// Other layout modes go here
} }
pub(crate) struct IndependentLayout { pub(crate) struct IndependentLayout {
@ -38,25 +59,6 @@ pub(crate) struct IndependentLayout {
pub content_block_size: Length, pub content_block_size: Length,
} }
// Private so that code outside of this module cannot match variants.
// It should got through methods instead.
#[derive(Debug, Serialize)]
enum IndependentFormattingContextContents {
Flow(BlockFormattingContext),
Flex(FlexContainer),
// Not called FC in specs, but behaves close enough
Replaced(ReplacedContent),
// Other layout modes go here
}
pub(crate) struct NonReplacedIFC<'a>(NonReplacedIFCKind<'a>);
enum NonReplacedIFCKind<'a> {
Flow(&'a BlockFormattingContext),
Flex(&'a FlexContainer),
}
impl IndependentFormattingContext { impl IndependentFormattingContext {
pub fn construct<'dom>( pub fn construct<'dom>(
context: &LayoutContext, context: &LayoutContext,
@ -76,12 +78,12 @@ impl IndependentFormattingContext {
content_sizes, content_sizes,
propagated_text_decoration_line, propagated_text_decoration_line,
); );
Self { 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,
contents: IndependentFormattingContextContents::Flow(bfc), contents: NonReplacedFormattingContextContents::Flow(bfc),
} })
}, },
DisplayInside::Flex => { DisplayInside::Flex => {
let (fc, content_sizes) = FlexContainer::construct( let (fc, content_sizes) = FlexContainer::construct(
@ -91,24 +93,19 @@ impl IndependentFormattingContext {
content_sizes, content_sizes,
propagated_text_decoration_line, propagated_text_decoration_line,
); );
Self { 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,
contents: IndependentFormattingContextContents::Flex(fc), contents: NonReplacedFormattingContextContents::Flex(fc),
} })
}, },
}, },
Err(replaced) => { Err(contents) => Self::Replaced(ReplacedFormattingContext {
let content_sizes =
content_sizes.compute(|| replaced.inline_content_sizes(&info.style));
Self {
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, contents,
contents: IndependentFormattingContextContents::Replaced(replaced), }),
}
},
} }
} }
@ -125,27 +122,37 @@ impl IndependentFormattingContext {
content_sizes, content_sizes,
propagated_text_decoration_line, propagated_text_decoration_line,
); );
Self { 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,
contents: IndependentFormattingContextContents::Flow(bfc), contents: NonReplacedFormattingContextContents::Flow(bfc),
})
}
pub fn style(&self) -> &Arc<ComputedValues> {
match self {
Self::NonReplaced(inner) => &inner.style,
Self::Replaced(inner) => &inner.style,
} }
} }
pub fn as_replaced(&self) -> Result<&ReplacedContent, NonReplacedIFC> { pub fn tag(&self) -> Tag {
use self::IndependentFormattingContextContents as Contents; match self {
use self::NonReplacedIFC as NR; Self::NonReplaced(inner) => inner.tag,
use self::NonReplacedIFCKind as Kind; Self::Replaced(inner) => inner.tag,
match &self.contents { }
Contents::Replaced(r) => Ok(r), }
Contents::Flow(f) => Err(NR(Kind::Flow(f))),
Contents::Flex(f) => Err(NR(Kind::Flex(f))), pub fn content_sizes(&self) -> ContentSizes {
match self {
Self::NonReplaced(inner) => inner.content_sizes.expect_inline().clone(),
Self::Replaced(inner) => inner.contents.inline_content_sizes(&inner.style),
} }
} }
} }
impl NonReplacedIFC<'_> { impl NonReplacedFormattingContext {
pub fn layout( pub fn layout(
&self, &self,
layout_context: &LayoutContext, layout_context: &LayoutContext,
@ -153,14 +160,14 @@ impl NonReplacedIFC<'_> {
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
tree_rank: usize, tree_rank: usize,
) -> IndependentLayout { ) -> IndependentLayout {
match &self.0 { match &self.contents {
NonReplacedIFCKind::Flow(bfc) => bfc.layout( NonReplacedFormattingContextContents::Flow(bfc) => bfc.layout(
layout_context, layout_context,
positioning_context, positioning_context,
containing_block, containing_block,
tree_rank, tree_rank,
), ),
NonReplacedIFCKind::Flex(fc) => fc.layout( NonReplacedFormattingContextContents::Flex(fc) => fc.layout(
layout_context, layout_context,
positioning_context, positioning_context,
containing_block, containing_block,

View file

@ -22,7 +22,7 @@ use style::Zero;
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub(crate) struct AbsolutelyPositionedBox { pub(crate) struct AbsolutelyPositionedBox {
pub contents: IndependentFormattingContext, pub context: IndependentFormattingContext,
} }
pub(crate) struct PositioningContext { pub(crate) struct PositioningContext {
@ -84,7 +84,7 @@ impl AbsolutelyPositionedBox {
!node_info.style.inline_box_offsets_are_both_non_auto(), !node_info.style.inline_box_offsets_are_both_non_auto(),
); );
Self { Self {
contents: IndependentFormattingContext::construct( context: IndependentFormattingContext::construct(
context, context,
node_info, node_info,
display_inside, display_inside,
@ -124,7 +124,7 @@ impl AbsolutelyPositionedBox {
let box_offsets = { let box_offsets = {
let box_ = self_.borrow(); let box_ = self_.borrow();
let box_offsets = box_.contents.style.box_offsets(containing_block); let box_offsets = box_.context.style().box_offsets(containing_block);
Vec2 { Vec2 {
inline: absolute_box_offsets( inline: absolute_box_offsets(
initial_start_corner.inline, initial_start_corner.inline,
@ -218,27 +218,6 @@ impl PositioningContext {
new_fragment new_fragment
} }
/// Given `fragment_layout_fn`, a closure which lays out a fragment in a provided
/// `PositioningContext`, create a positioning context for a positioned fragment and lay out
/// the fragment and all its children. Returns the resulting `BoxFragment`.
fn create_and_layout_positioned(
layout_context: &LayoutContext,
style: &ComputedValues,
for_nearest_containing_block_for_all_descendants: &mut Vec<HoistedAbsolutelyPositionedBox>,
fragment_layout_fn: impl FnOnce(&mut Self) -> BoxFragment,
) -> BoxFragment {
let mut new_context = match Self::new_for_style(style) {
Some(new_context) => new_context,
None => unreachable!(),
};
let mut new_fragment = fragment_layout_fn(&mut new_context);
new_context.layout_collected_children(layout_context, &mut new_fragment);
for_nearest_containing_block_for_all_descendants
.extend(new_context.for_nearest_containing_block_for_all_descendants);
new_fragment
}
// Lay out the hoisted boxes collected into this `PositioningContext` and add them // Lay out the hoisted boxes collected into this `PositioningContext` and add them
// to the given `BoxFragment`. // to the given `BoxFragment`.
pub fn layout_collected_children( pub fn layout_collected_children(
@ -288,8 +267,8 @@ impl PositioningContext {
let position = box_ let position = box_
.absolutely_positioned_box .absolutely_positioned_box
.borrow() .borrow()
.contents .context
.style .style()
.clone_position(); .clone_position();
match position { match position {
Position::Fixed => {}, // fall through Position::Fixed => {}, // fall through
@ -416,29 +395,30 @@ impl HoistedAbsolutelyPositionedBox {
) -> BoxFragment { ) -> BoxFragment {
let cbis = containing_block.size.inline; let cbis = containing_block.size.inline;
let cbbs = containing_block.size.block; let cbbs = containing_block.size.block;
let absolutely_positioned_box = self.absolutely_positioned_box.borrow_mut(); let mut absolutely_positioned_box = self.absolutely_positioned_box.borrow_mut();
let style = &absolutely_positioned_box.contents.style; let pbm = absolutely_positioned_box
let pbm = style.padding_border_margin(&containing_block.into()); .context
.style()
.padding_border_margin(&containing_block.into());
let size; let size = match &absolutely_positioned_box.context {
let replaced_used_size; IndependentFormattingContext::Replaced(replaced) => {
match absolutely_positioned_box.contents.as_replaced() {
Ok(replaced) => {
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-width // https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-height // https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
let used_size = let used_size = replaced.contents.used_size_as_if_inline_element(
replaced.used_size_as_if_inline_element(&containing_block.into(), style, &pbm); &containing_block.into(),
size = Vec2 { &replaced.style,
&pbm,
);
Vec2 {
inline: LengthOrAuto::LengthPercentage(used_size.inline), inline: LengthOrAuto::LengthPercentage(used_size.inline),
block: LengthOrAuto::LengthPercentage(used_size.block), block: LengthOrAuto::LengthPercentage(used_size.block),
};
replaced_used_size = Some(used_size);
},
Err(_non_replaced) => {
size = style.content_box_size(&containing_block.into(), &pbm);
replaced_used_size = None;
},
} }
},
IndependentFormattingContext::NonReplaced(non_replaced) => non_replaced
.style
.content_box_size(&containing_block.into(), &pbm),
};
let inline_axis = solve_axis( let inline_axis = solve_axis(
cbis, cbis,
@ -467,22 +447,22 @@ impl HoistedAbsolutelyPositionedBox {
block_end: block_axis.margin_end, block_end: block_axis.margin_end,
}; };
PositioningContext::create_and_layout_positioned( let mut positioning_context =
layout_context, PositioningContext::new_for_style(absolutely_positioned_box.context.style()).unwrap();
style, let mut new_fragment = {
for_nearest_containing_block_for_all_descendants, let content_size;
|positioning_context| {
let size;
let fragments; let fragments;
match absolutely_positioned_box.contents.as_replaced() { match &mut absolutely_positioned_box.context {
Ok(replaced) => { IndependentFormattingContext::Replaced(replaced) => {
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-width // https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-height // https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
let style = &absolutely_positioned_box.contents.style; let style = &replaced.style;
size = replaced_used_size.unwrap(); content_size = size.auto_is(|| unreachable!());
fragments = replaced.make_fragments(style, size.clone()); fragments = replaced
.contents
.make_fragments(style, content_size.clone());
}, },
Err(non_replaced) => { IndependentFormattingContext::NonReplaced(non_replaced) => {
// https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width // https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width
// https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-height // https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-height
let inline_size = inline_axis.size.auto_is(|| { let inline_size = inline_axis.size.auto_is(|| {
@ -490,20 +470,15 @@ impl HoistedAbsolutelyPositionedBox {
Anchor::Start(start) => start, Anchor::Start(start) => start,
Anchor::End(end) => end, Anchor::End(end) => end,
}; };
let available_size = cbis - let available_size =
anchor - cbis - anchor - pbm.padding_border_sums.inline - margin.inline_sum();
pbm.padding_border_sums.inline - non_replaced.content_sizes.shrink_to_fit(available_size)
margin.inline_sum();
absolutely_positioned_box
.contents
.content_sizes
.shrink_to_fit(available_size)
}); });
let containing_block_for_children = ContainingBlock { let containing_block_for_children = ContainingBlock {
inline_size, inline_size,
block_size: block_axis.size, block_size: block_axis.size,
style, style: &non_replaced.style,
}; };
// https://drafts.csswg.org/css-writing-modes/#orthogonal-flows // https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
assert_eq!( assert_eq!(
@ -514,12 +489,12 @@ impl HoistedAbsolutelyPositionedBox {
let dummy_tree_rank = 0; let dummy_tree_rank = 0;
let independent_layout = non_replaced.layout( let independent_layout = non_replaced.layout(
layout_context, layout_context,
positioning_context, &mut positioning_context,
&containing_block_for_children, &containing_block_for_children,
dummy_tree_rank, dummy_tree_rank,
); );
size = Vec2 { content_size = Vec2 {
inline: inline_size, inline: inline_size,
block: block_axis block: block_axis
.size .size
@ -533,12 +508,14 @@ impl HoistedAbsolutelyPositionedBox {
let inline_start = match inline_axis.anchor { let inline_start = match inline_axis.anchor {
Anchor::Start(start) => start + pb.inline_start + margin.inline_start, Anchor::Start(start) => start + pb.inline_start + margin.inline_start,
Anchor::End(end) => { Anchor::End(end) => {
cbis - end - pb.inline_end - margin.inline_end - size.inline cbis - end - pb.inline_end - margin.inline_end - content_size.inline
}, },
}; };
let block_start = match block_axis.anchor { let block_start = match block_axis.anchor {
Anchor::Start(start) => start + pb.block_start + margin.block_start, Anchor::Start(start) => start + pb.block_start + margin.block_start,
Anchor::End(end) => cbbs - end - pb.block_end - margin.block_end - size.block, Anchor::End(end) => {
cbbs - end - pb.block_end - margin.block_end - content_size.block
},
}; };
let content_rect = Rect { let content_rect = Rect {
@ -546,12 +523,12 @@ impl HoistedAbsolutelyPositionedBox {
inline: inline_start, inline: inline_start,
block: block_start, block: block_start,
}, },
size, size: content_size,
}; };
BoxFragment::new( BoxFragment::new(
absolutely_positioned_box.contents.tag, absolutely_positioned_box.context.tag(),
style.clone(), absolutely_positioned_box.context.style().clone(),
fragments, fragments,
content_rect, content_rect,
pbm.padding, pbm.padding,
@ -559,8 +536,11 @@ impl HoistedAbsolutelyPositionedBox {
margin, margin,
CollapsedBlockMargins::zero(), CollapsedBlockMargins::zero(),
) )
}, };
) positioning_context.layout_collected_children(layout_context, &mut new_fragment);
for_nearest_containing_block_for_all_descendants
.extend(positioning_context.for_nearest_containing_block_for_all_descendants);
new_fragment
} }
} }

View file

@ -64,7 +64,7 @@ impl ContentSizes {
} }
} }
fn map(&self, f: impl Fn(Length) -> Length) -> Self { pub fn map(&self, f: impl Fn(Length) -> Length) -> Self {
Self { Self {
min_content: f(self.min_content), min_content: f(self.min_content),
max_content: f(self.max_content), max_content: f(self.max_content),
@ -98,29 +98,37 @@ pub(crate) enum BoxContentSizes {
} }
impl BoxContentSizes { impl BoxContentSizes {
fn expect_inline(&self) -> &ContentSizes { pub fn expect_inline(&self) -> &ContentSizes {
match self { match self {
Self::NoneWereRequested => panic!("Accessing content size that was not requested"), Self::NoneWereRequested => panic!("Accessing content size that was not requested"),
Self::Inline(s) => s, Self::Inline(s) => s,
} }
} }
/// https://dbaron.org/css/intrinsic/#outer-intrinsic /// https://drafts.csswg.org/css2/visudet.html#shrink-to-fit-float
pub fn outer_inline( pub(crate) fn shrink_to_fit(&self, available_size: Length) -> Length {
&self, let inline = self.expect_inline();
available_size
.max(inline.min_content)
.min(inline.max_content)
}
}
pub(crate) fn outer_inline(
style: &ComputedValues, style: &ComputedValues,
containing_block_writing_mode: WritingMode, containing_block_writing_mode: WritingMode,
get_content_size: impl FnOnce() -> ContentSizes,
) -> ContentSizes { ) -> ContentSizes {
let (mut outer, percentages) = let (mut outer, percentages) =
self.outer_inline_and_percentages(style, containing_block_writing_mode); outer_inline_and_percentages(style, containing_block_writing_mode, get_content_size);
outer.adjust_for_pbm_percentages(percentages); outer.adjust_for_pbm_percentages(percentages);
outer outer
} }
pub(crate) fn outer_inline_and_percentages( pub(crate) fn outer_inline_and_percentages(
&self,
style: &ComputedValues, style: &ComputedValues,
containing_block_writing_mode: WritingMode, containing_block_writing_mode: WritingMode,
get_content_size: impl FnOnce() -> ContentSizes,
) -> (ContentSizes, Percentage) { ) -> (ContentSizes, Percentage) {
let padding = style.padding(containing_block_writing_mode); let padding = style.padding(containing_block_writing_mode);
let border = style.border_width(containing_block_writing_mode); let border = style.border_width(containing_block_writing_mode);
@ -174,7 +182,7 @@ impl BoxContentSizes {
max_content: border_box_size, max_content: border_box_size,
} }
}, },
None => self.expect_inline().map(|content_box_size| { None => get_content_size().map(|content_box_size| {
match box_sizing { match box_sizing {
// Clamp to 'min-width' and 'max-width', which are sizing the… // Clamp to 'min-width' and 'max-width', which are sizing the…
BoxSizing::ContentBox => clamp(content_box_size) + pb_lengths, BoxSizing::ContentBox => clamp(content_box_size) + pb_lengths,
@ -186,12 +194,3 @@ impl BoxContentSizes {
let outer = border_box_sizes.map(|s| s + m_lengths); let outer = border_box_sizes.map(|s| s + m_lengths);
(outer, pbm_percentages) (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)
}
}