Make IndependentFormattingContext an enum

This commit is contained in:
Anthony Ramine 2020-06-15 14:40:01 +02:00
parent 07d8c28d4a
commit db80b8e3c1
6 changed files with 183 additions and 163 deletions

View file

@ -204,7 +204,7 @@ where
// https://drafts.csswg.org/css-flexbox/#order-modified-document-order
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
// as having order: 0 for the purpose of determining their painting order

View file

@ -723,7 +723,7 @@ where
max_assign_in_flow_outer_content_sizes_to.is_some() &&
!info.style.inline_size_is_length(),
);
let contents = IndependentFormattingContext::construct(
let context = IndependentFormattingContext::construct(
context,
info,
display_inside,
@ -733,13 +733,13 @@ where
);
if let Some(to) = max_assign_in_flow_outer_content_sizes_to {
to.max_assign(&sizing::outer_inline(
&contents.style,
&context.style(),
not_actually_containing_block_writing_mode,
|| contents.content_sizes.expect_inline().clone(),
|| context.content_sizes(),
))
}
(
ArcRefCell::new(BlockLevelBox::Independent(contents)),
ArcRefCell::new(BlockLevelBox::Independent(context)),
ContainsFloats::No,
)
},

View file

@ -155,7 +155,7 @@ impl InlineFormattingContext {
impl Computation<'_> {
fn traverse(&mut self, inline_level_boxes: &[ArcRefCell<InlineLevelBox>]) {
for inline_level_box in inline_level_boxes {
match &*inline_level_box.borrow() {
match &mut *inline_level_box.borrow_mut() {
InlineLevelBox::InlineBox(inline_box) => {
let padding =
inline_box.style.padding(self.containing_block_writing_mode);
@ -201,9 +201,9 @@ impl InlineFormattingContext {
},
InlineLevelBox::Atomic(atomic) => {
let (outer, pc) = sizing::outer_inline_and_percentages(
&atomic.style,
&atomic.style(),
self.containing_block_writing_mode,
|| atomic.content_sizes.expect_inline().clone(),
|| atomic.content_sizes(),
);
self.current_line.min_content += outer.min_content;
self.current_line.max_content += outer.max_content;
@ -295,7 +295,7 @@ impl InlineFormattingContext {
InlineLevelBox::TextRun(run) => run.layout(layout_context, &mut ifc),
InlineLevelBox::Atomic(a) => layout_atomic(layout_context, &mut ifc, a),
InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
let style = AtomicRef::map(box_.borrow(), |box_| &box_.context.style);
let style = AtomicRef::map(box_.borrow(), |box_| box_.context.style());
let initial_start_corner =
match Display::from(style.get_box().original_display) {
Display::GeneratingBox(DisplayGeneratingBox::OutsideInside {
@ -545,7 +545,8 @@ fn layout_atomic(
ifc: &mut InlineFormattingContextState,
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 pbm_sums = &(&pbm.padding + &pbm.border) + &margin;
ifc.inline_position += pbm_sums.inline_start;
@ -553,19 +554,24 @@ fn layout_atomic(
block: pbm_sums.block_start,
inline: ifc.inline_position - ifc.current_nesting_level.inline_start,
};
if atomic.style.clone_position().is_relative() {
start_corner += &relative_adjustement(&atomic.style, ifc.containing_block)
if style.clone_position().is_relative() {
start_corner += &relative_adjustement(&style, ifc.containing_block)
}
let fragment = match atomic.contents.as_replaced() {
Ok(replaced) => {
let size =
replaced.used_size_as_if_inline_element(ifc.containing_block, &atomic.style, &pbm);
let fragments = replaced.make_fragments(&atomic.style, size.clone());
let fragment = match atomic {
IndependentFormattingContext::Replaced(replaced) => {
let size = replaced.contents.used_size_as_if_inline_element(
ifc.containing_block,
&replaced.style,
&pbm,
);
let fragments = replaced
.contents
.make_fragments(&replaced.style, size.clone());
let content_rect = Rect { start_corner, size };
BoxFragment::new(
atomic.tag,
atomic.style.clone(),
replaced.tag,
replaced.style.clone(),
fragments,
content_rect,
pbm.padding,
@ -574,12 +580,14 @@ fn layout_atomic(
CollapsedBlockMargins::zero(),
)
},
Err(non_replaced) => {
let box_size = atomic.style.content_box_size(&ifc.containing_block, &pbm);
let max_box_size = atomic
IndependentFormattingContext::NonReplaced(non_replaced) => {
let box_size = non_replaced
.style
.content_box_size(&ifc.containing_block, &pbm);
let max_box_size = non_replaced
.style
.content_max_box_size(&ifc.containing_block, &pbm);
let min_box_size = atomic
let min_box_size = non_replaced
.style
.content_min_box_size(&ifc.containing_block, &pbm)
.auto_is(Length::zero);
@ -587,7 +595,7 @@ fn layout_atomic(
// https://drafts.csswg.org/css2/visudet.html#inlineblock-width
let tentative_inline_size = box_size.inline.auto_is(|| {
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
@ -599,7 +607,7 @@ fn layout_atomic(
let containing_block_for_children = ContainingBlock {
inline_size,
block_size: box_size.block,
style: &atomic.style,
style: &non_replaced.style,
};
assert_eq!(
ifc.containing_block.style.writing_mode,
@ -635,8 +643,8 @@ fn layout_atomic(
},
};
BoxFragment::new(
atomic.tag,
atomic.style.clone(),
non_replaced.tag,
non_replaced.style.clone(),
independent_layout.fragments,
content_rect,
pbm.padding,

View file

@ -8,7 +8,9 @@ use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
use crate::flow::float::{FloatBox, FloatContext};
use crate::flow::inline::InlineFormattingContext;
use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout, NonReplacedIFC};
use crate::formatting_contexts::{
IndependentFormattingContext, IndependentLayout, NonReplacedFormattingContext,
};
use crate::fragments::{
AbsoluteOrFixedPositionedFragment, AnonymousFragment, BoxFragment, CollapsedBlockMargins,
CollapsedMargin, Fragment, Tag,
@ -288,32 +290,43 @@ impl BlockLevelBox {
)
},
)),
BlockLevelBox::Independent(independent) => {
Fragment::Box(positioning_context.layout_maybe_position_relative_fragment(
layout_context,
containing_block,
&independent.style,
|positioning_context| match independent.contents.as_replaced() {
Ok(replaced) => layout_in_flow_replaced_block_level(
containing_block,
independent.tag,
&independent.style,
replaced,
),
Err(non_replaced) => layout_in_flow_non_replaced_block_level(
layout_context,
positioning_context,
containing_block,
independent.tag,
&independent.style,
NonReplacedContents::EstablishesAnIndependentFormattingContext(
non_replaced,
),
tree_rank,
float_context,
),
},
))
BlockLevelBox::Independent(independent) => match independent {
IndependentFormattingContext::Replaced(replaced) => {
Fragment::Box(positioning_context.layout_maybe_position_relative_fragment(
layout_context,
containing_block,
&replaced.style,
|_positioning_context| {
layout_in_flow_replaced_block_level(
containing_block,
replaced.tag,
&replaced.style,
&replaced.contents,
)
},
))
},
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,
positioning_context,
containing_block,
non_replaced.tag,
&non_replaced.style,
NonReplacedContents::EstablishesAnIndependentFormattingContext(
non_replaced,
),
tree_rank,
float_context,
)
},
))
},
},
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
let hoisted_box = AbsolutelyPositionedBox::to_hoisted(
@ -326,7 +339,7 @@ impl BlockLevelBox {
positioning_context.push(hoisted_box);
Fragment::AbsoluteOrFixedPositioned(AbsoluteOrFixedPositionedFragment {
hoisted_fragment,
position: box_.borrow().context.style.clone_position(),
position: box_.borrow().context.style().clone_position(),
})
},
BlockLevelBox::OutOfFlowFloatBox(_box_) => {
@ -341,7 +354,7 @@ impl BlockLevelBox {
enum NonReplacedContents<'a> {
SameFormattingContextBlock(&'a BlockContainer),
EstablishesAnIndependentFormattingContext(NonReplacedIFC<'a>),
EstablishesAnIndependentFormattingContext(&'a NonReplacedFormattingContext),
}
/// 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::positioned::PositioningContext;
use crate::replaced::ReplacedContent;
use crate::sizing::{BoxContentSizes, ContentSizesRequest};
use crate::sizing::{BoxContentSizes, ContentSizes, ContentSizesRequest};
use crate::style_ext::DisplayInside;
use crate::ContainingBlock;
use servo_arc::Arc;
@ -20,15 +20,36 @@ use style::values::specified::text::TextDecorationLine;
/// https://drafts.csswg.org/css-display/#independent-formatting-context
#[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,
#[serde(skip_serializing)]
pub style: Arc<ComputedValues>,
/// If it was requested during construction
pub content_sizes: BoxContentSizes,
pub contents: NonReplacedFormattingContextContents,
}
pub 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 {
@ -38,28 +59,6 @@ pub(crate) struct IndependentLayout {
pub content_block_size: Length,
}
#[derive(Debug, Serialize)]
pub(crate) struct IndependentFormattingContextContents(IndependentFormattingContextContentsKind);
// Private so that code outside of this module cannot match variants.
// It should got through methods instead.
#[derive(Debug, Serialize)]
enum IndependentFormattingContextContentsKind {
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 {
pub fn construct<'dom>(
context: &LayoutContext,
@ -79,14 +78,12 @@ impl IndependentFormattingContext {
content_sizes,
propagated_text_decoration_line,
);
Self {
Self::NonReplaced(NonReplacedFormattingContext {
tag: Tag::from_node_and_style_info(info),
style: Arc::clone(&info.style),
content_sizes,
contents: IndependentFormattingContextContents(
IndependentFormattingContextContentsKind::Flow(bfc),
),
}
contents: NonReplacedFormattingContextContents::Flow(bfc),
})
},
DisplayInside::Flex => {
let (fc, content_sizes) = FlexContainer::construct(
@ -96,28 +93,19 @@ impl IndependentFormattingContext {
content_sizes,
propagated_text_decoration_line,
);
Self {
Self::NonReplaced(NonReplacedFormattingContext {
tag: Tag::from_node_and_style_info(info),
style: Arc::clone(&info.style),
content_sizes,
contents: IndependentFormattingContextContents(
IndependentFormattingContextContentsKind::Flex(fc),
),
}
contents: NonReplacedFormattingContextContents::Flex(fc),
})
},
},
Err(replaced) => {
let content_sizes =
content_sizes.compute(|| replaced.inline_content_sizes(&info.style));
Self {
tag: Tag::from_node_and_style_info(info),
style: Arc::clone(&info.style),
content_sizes,
contents: IndependentFormattingContextContents(
IndependentFormattingContextContentsKind::Replaced(replaced),
),
}
},
Err(contents) => Self::Replaced(ReplacedFormattingContext {
tag: Tag::from_node_and_style_info(info),
style: Arc::clone(&info.style),
contents,
}),
}
}
@ -134,31 +122,37 @@ impl IndependentFormattingContext {
content_sizes,
propagated_text_decoration_line,
);
Self {
Self::NonReplaced(NonReplacedFormattingContext {
tag: Tag::from_node_and_style_info(info),
style: Arc::clone(&info.style),
content_sizes,
contents: IndependentFormattingContextContents(
IndependentFormattingContextContentsKind::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 tag(&self) -> Tag {
match self {
Self::NonReplaced(inner) => inner.tag,
Self::Replaced(inner) => inner.tag,
}
}
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 IndependentFormattingContextContents {
pub fn as_replaced(&self) -> Result<&ReplacedContent, NonReplacedIFC<'_>> {
use self::IndependentFormattingContextContentsKind as Contents;
use self::NonReplacedIFC as NR;
use self::NonReplacedIFCKind as Kind;
match &self.0 {
Contents::Replaced(r) => Ok(r),
Contents::Flow(f) => Err(NR(Kind::Flow(f))),
Contents::Flex(f) => Err(NR(Kind::Flex(f))),
}
}
}
impl NonReplacedIFC<'_> {
impl NonReplacedFormattingContext {
pub fn layout(
&self,
layout_context: &LayoutContext,
@ -166,14 +160,14 @@ impl NonReplacedIFC<'_> {
containing_block: &ContainingBlock,
tree_rank: usize,
) -> IndependentLayout {
match &self.0 {
NonReplacedIFCKind::Flow(bfc) => bfc.layout(
match &self.contents {
NonReplacedFormattingContextContents::Flow(bfc) => bfc.layout(
layout_context,
positioning_context,
containing_block,
tree_rank,
),
NonReplacedIFCKind::Flex(fc) => fc.layout(
NonReplacedFormattingContextContents::Flex(fc) => fc.layout(
layout_context,
positioning_context,
containing_block,

View file

@ -124,7 +124,7 @@ impl AbsolutelyPositionedBox {
let box_offsets = {
let box_ = self_.borrow();
let box_offsets = box_.context.style.box_offsets(containing_block);
let box_offsets = box_.context.style().box_offsets(containing_block);
Vec2 {
inline: absolute_box_offsets(
initial_start_corner.inline,
@ -268,7 +268,7 @@ impl PositioningContext {
.absolutely_positioned_box
.borrow()
.context
.style
.style()
.clone_position();
match position {
Position::Fixed => {}, // fall through
@ -395,29 +395,30 @@ impl HoistedAbsolutelyPositionedBox {
) -> BoxFragment {
let cbis = containing_block.size.inline;
let cbbs = containing_block.size.block;
let absolutely_positioned_box = self.absolutely_positioned_box.borrow_mut();
let style = &absolutely_positioned_box.context.style;
let pbm = style.padding_border_margin(&containing_block.into());
let mut absolutely_positioned_box = self.absolutely_positioned_box.borrow_mut();
let pbm = absolutely_positioned_box
.context
.style()
.padding_border_margin(&containing_block.into());
let size;
let replaced_used_size;
match absolutely_positioned_box.context.contents.as_replaced() {
Ok(replaced) => {
let size = match &absolutely_positioned_box.context {
IndependentFormattingContext::Replaced(replaced) => {
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
let used_size =
replaced.used_size_as_if_inline_element(&containing_block.into(), style, &pbm);
size = Vec2 {
let used_size = replaced.contents.used_size_as_if_inline_element(
&containing_block.into(),
&replaced.style,
&pbm,
);
Vec2 {
inline: LengthOrAuto::LengthPercentage(used_size.inline),
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(
cbis,
@ -446,19 +447,22 @@ impl HoistedAbsolutelyPositionedBox {
block_end: block_axis.margin_end,
};
let mut positioning_context = PositioningContext::new_for_style(style).unwrap();
let mut positioning_context =
PositioningContext::new_for_style(absolutely_positioned_box.context.style()).unwrap();
let mut new_fragment = {
let size;
let content_size;
let fragments;
match absolutely_positioned_box.context.contents.as_replaced() {
Ok(replaced) => {
match &mut absolutely_positioned_box.context {
IndependentFormattingContext::Replaced(replaced) => {
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
let style = &absolutely_positioned_box.context.style;
size = replaced_used_size.unwrap();
fragments = replaced.make_fragments(style, size.clone());
let style = &replaced.style;
content_size = size.auto_is(|| unreachable!());
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-height
let inline_size = inline_axis.size.auto_is(|| {
@ -468,16 +472,13 @@ impl HoistedAbsolutelyPositionedBox {
};
let available_size =
cbis - anchor - pbm.padding_border_sums.inline - margin.inline_sum();
absolutely_positioned_box
.context
.content_sizes
.shrink_to_fit(available_size)
non_replaced.content_sizes.shrink_to_fit(available_size)
});
let containing_block_for_children = ContainingBlock {
inline_size,
block_size: block_axis.size,
style,
style: &non_replaced.style,
};
// https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
assert_eq!(
@ -493,7 +494,7 @@ impl HoistedAbsolutelyPositionedBox {
dummy_tree_rank,
);
size = Vec2 {
content_size = Vec2 {
inline: inline_size,
block: block_axis
.size
@ -506,11 +507,15 @@ impl HoistedAbsolutelyPositionedBox {
let pb = &pbm.padding + &pbm.border;
let inline_start = match inline_axis.anchor {
Anchor::Start(start) => start + pb.inline_start + margin.inline_start,
Anchor::End(end) => cbis - end - pb.inline_end - margin.inline_end - size.inline,
Anchor::End(end) => {
cbis - end - pb.inline_end - margin.inline_end - content_size.inline
},
};
let block_start = match block_axis.anchor {
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 {
@ -518,12 +523,12 @@ impl HoistedAbsolutelyPositionedBox {
inline: inline_start,
block: block_start,
},
size,
size: content_size,
};
BoxFragment::new(
absolutely_positioned_box.context.tag,
style.clone(),
absolutely_positioned_box.context.tag(),
absolutely_positioned_box.context.style().clone(),
fragments,
content_rect,
pbm.padding,