layout: Add LayoutBoxBase and use it for IndependentFormattingContext (#34507)

Add a new struct `LayoutBoxBase`, that will be used throughout the box
tree. The idea of this struct is that we have a place to consistently
store common layout information (style and node information) and also to
cache layout results such as content sizes (inline and maybe later box
sizes) and eventually layout results.

In addition to the addition of this struct,
`IndependentFormattingContext` is flattened slightly so that it directly
holds the contents of both replaced and non-replaced elements.

This is only added to independent formatting contexts, but will later be
added to all block containers as well.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2024-12-07 20:12:25 +01:00 committed by GitHub
parent 97e9841d47
commit 264c0f972f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 425 additions and 441 deletions

View file

@ -15,9 +15,10 @@ use crate::dom_traversal::{Contents, NodeAndStyleInfo, TraversalHandler};
use crate::flow::inline::construct::InlineFormattingContextBuilder;
use crate::flow::{BlockContainer, BlockFormattingContext};
use crate::formatting_contexts::{
IndependentFormattingContext, NonReplacedFormattingContext,
NonReplacedFormattingContextContents,
IndependentFormattingContext, IndependentFormattingContextContents,
IndependentNonReplacedContents,
};
use crate::layout_box_base::LayoutBoxBase;
use crate::style_ext::DisplayGeneratingBox;
/// <https://drafts.csswg.org/css-flexbox/#flex-items>
@ -173,16 +174,12 @@ where
BlockContainer::InlineFormattingContext(inline_formatting_context),
);
let info = &self.info.new_anonymous(anonymous_style.clone().unwrap());
let non_replaced = NonReplacedFormattingContext {
base_fragment_info: info.into(),
style: info.style.clone(),
content_sizes_result: Default::default(),
contents: NonReplacedFormattingContextContents::Flow(
block_formatting_context,
let formatting_context = IndependentFormattingContext {
base: LayoutBoxBase::new(info.into(), info.style.clone()),
contents: IndependentFormattingContextContents::NonReplaced(
IndependentNonReplacedContents::Flow(block_formatting_context),
),
};
let formatting_context =
IndependentFormattingContext::NonReplaced(non_replaced);
Some(ModernItem {
kind: ModernItemKind::InFlow,

View file

@ -16,7 +16,7 @@ use style::values::generics::counters::{Content, ContentItem};
use crate::context::LayoutContext;
use crate::dom::{BoxSlot, LayoutBox, NodeExt};
use crate::fragment_tree::{BaseFragmentInfo, FragmentFlags, Tag};
use crate::replaced::ReplacedContent;
use crate::replaced::ReplacedContents;
use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside, DisplayOutside};
#[derive(Clone, Copy, Debug)]
@ -126,7 +126,7 @@ pub(super) enum Contents {
NonReplaced(NonReplacedContents),
/// Example: an `<img src=…>` element.
/// <https://drafts.csswg.org/css2/conform.html#replaced-element>
Replaced(ReplacedContent),
Replaced(ReplacedContents),
}
#[derive(Debug)]
@ -141,7 +141,7 @@ pub(super) enum NonReplacedContents {
#[derive(Debug)]
pub(super) enum PseudoElementContentItem {
Text(String),
Replaced(ReplacedContent),
Replaced(ReplacedContents),
}
pub(super) trait TraversalHandler<'dom, Node>
@ -216,7 +216,7 @@ fn traverse_element<'dom, Node>(
) where
Node: NodeExt<'dom>,
{
let replaced = ReplacedContent::for_element(element, context);
let replaced = ReplacedContents::for_element(element, context);
let style = element.style(context);
match Display::from(style.get_box().display) {
Display::None => element.unset_all_boxes(),
@ -421,7 +421,7 @@ where
},
ContentItem::Image(image) => {
if let Some(replaced_content) =
ReplacedContent::from_image(element, context, image)
ReplacedContents::from_image(element, context, image)
{
vec.push(PseudoElementContentItem::Replaced(replaced_content));
}

View file

@ -30,7 +30,9 @@ use super::{
};
use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
use crate::formatting_contexts::{Baselines, IndependentFormattingContext, IndependentLayout};
use crate::formatting_contexts::{
Baselines, IndependentFormattingContextContents, IndependentLayout,
};
use crate::fragment_tree::{BoxFragment, CollapsedBlockMargins, Fragment, FragmentFlags};
use crate::geom::{AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, Size};
use crate::positioned::{
@ -1893,8 +1895,8 @@ impl FlexItem<'_> {
}),
};
let context = &self.box_.independent_formatting_context;
let item_writing_mode = context.style().writing_mode;
let independent_formatting_context = &self.box_.independent_formatting_context;
let item_writing_mode = independent_formatting_context.style().writing_mode;
let item_is_horizontal = item_writing_mode.is_horizontal();
let flex_axis = flex_context.config.flex_axis;
let cross_axis_is_item_block_axis = cross_axis_is_item_block_axis(
@ -1922,7 +1924,7 @@ impl FlexItem<'_> {
item_writing_mode,
self.preferred_aspect_ratio,
);
context
independent_formatting_context
.inline_content_sizes(flex_context.layout_context, &constraint_space)
.sizes
.shrink_to_fit(stretch_size)
@ -1945,26 +1947,25 @@ impl FlexItem<'_> {
};
let container_writing_mode = containing_block.style.writing_mode;
match context {
IndependentFormattingContext::Replaced(replaced) => {
let size = replaced
.contents
.used_size_as_if_inline_element_from_content_box_sizes(
containing_block,
&replaced.style,
self.preferred_aspect_ratio,
LogicalVec2 {
inline: Size::Numeric(inline_size),
block: block_size.non_auto().map_or(Size::Initial, Size::Numeric),
},
flex_axis
.vec2_to_flow_relative(self.content_min_size)
.map(|size| Size::Numeric(*size)),
flex_axis
.vec2_to_flow_relative(self.content_max_size)
.map(|size| size.map_or(Size::Initial, Size::Numeric)),
flex_axis.vec2_to_flow_relative(self.pbm_auto_is_zero),
);
let item_style = independent_formatting_context.style();
match &independent_formatting_context.contents {
IndependentFormattingContextContents::Replaced(replaced) => {
let size = replaced.used_size_as_if_inline_element_from_content_box_sizes(
containing_block,
item_style,
self.preferred_aspect_ratio,
LogicalVec2 {
inline: Size::Numeric(inline_size),
block: block_size.non_auto().map_or(Size::Initial, Size::Numeric),
},
flex_axis
.vec2_to_flow_relative(self.content_min_size)
.map(|size| Size::Numeric(*size)),
flex_axis
.vec2_to_flow_relative(self.content_max_size)
.map(|size| size.map_or(Size::Initial, Size::Numeric)),
flex_axis.vec2_to_flow_relative(self.pbm_auto_is_zero),
);
let hypothetical_cross_size = flex_axis.vec2_to_flex_relative(size).cross;
if let Some(non_stretch_layout_result) = non_stretch_layout_result {
@ -1979,10 +1980,8 @@ impl FlexItem<'_> {
}
}
let fragments = replaced.contents.make_fragments(
&replaced.style,
size.to_physical_size(container_writing_mode),
);
let fragments = replaced
.make_fragments(item_style, size.to_physical_size(container_writing_mode));
Some(FlexItemLayoutResult {
hypothetical_cross_size,
@ -2000,7 +1999,7 @@ impl FlexItem<'_> {
baseline_relative_to_margin_box: None,
})
},
IndependentFormattingContext::NonReplaced(non_replaced) => {
IndependentFormattingContextContents::NonReplaced(non_replaced) => {
let calculate_hypothetical_cross_size = |content_block_size| {
self.content_box_size
.cross
@ -2020,7 +2019,7 @@ impl FlexItem<'_> {
let item_as_containing_block = ContainingBlock {
inline_size,
block_size,
style: &non_replaced.style,
style: item_style,
};
if let Some(non_stretch_layout_result) = non_stretch_layout_result {
@ -2067,7 +2066,7 @@ impl FlexItem<'_> {
let item_writing_mode_is_orthogonal_to_container_writing_mode =
flex_context.config.writing_mode.is_horizontal() !=
non_replaced.style.writing_mode.is_horizontal();
item_style.writing_mode.is_horizontal();
let has_compatible_baseline = match flex_axis {
FlexAxis::Row => !item_writing_mode_is_orthogonal_to_container_writing_mode,
FlexAxis::Column => item_writing_mode_is_orthogonal_to_container_writing_mode,
@ -2752,8 +2751,9 @@ impl FlexItemBox {
.collects_for_nearest_positioned_ancestor(),
);
match &self.independent_formatting_context {
IndependentFormattingContext::Replaced(replaced) => {
let style = self.independent_formatting_context.style();
match &self.independent_formatting_context.contents {
IndependentFormattingContextContents::Replaced(replaced) => {
content_box_size.inline = content_box_size.inline.map(|v| v.max(Au::zero()));
if intrinsic_sizing_mode == IntrinsicSizingMode::Size {
content_box_size.block = AuOrAuto::Auto;
@ -2761,10 +2761,9 @@ impl FlexItemBox {
max_size.block = None;
}
replaced
.contents
.used_size_as_if_inline_element_from_content_box_sizes(
flex_context.containing_block,
&replaced.style,
style,
preferred_aspect_ratio,
content_box_size
.map(|size| size.non_auto().map_or(Size::Initial, Size::Numeric)),
@ -2775,7 +2774,7 @@ impl FlexItemBox {
)
.block
},
IndependentFormattingContext::NonReplaced(non_replaced) => {
IndependentFormattingContextContents::NonReplaced(non_replaced) => {
// TODO: This is wrong if the item writing mode is different from the flex
// container's writing mode.
let inline_size = content_box_size
@ -2792,7 +2791,7 @@ impl FlexItemBox {
} else {
let constraint_space = ConstraintSpace::new(
SizeConstraint::default(),
non_replaced.style.writing_mode,
style.writing_mode,
non_replaced.preferred_aspect_ratio(),
);
non_replaced
@ -2808,7 +2807,7 @@ impl FlexItemBox {
let item_as_containing_block = ContainingBlock {
inline_size,
block_size: AuOrAuto::Auto,
style: &non_replaced.style,
style,
};
let content_block_size = || {
if let Some(cache) = &*self.block_content_size_cache.borrow() {

View file

@ -111,13 +111,14 @@ use webrender_api::FontInstanceKey;
use xi_unicode::linebreak_property;
use super::float::{Clear, PlacementAmongFloats};
use super::IndependentFormattingContextContents;
use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
use crate::flow::float::{FloatBox, SequentialLayoutState};
use crate::flow::{CollapsibleWithParentStartMargin, FlowLayout};
use crate::formatting_contexts::{
Baselines, IndependentFormattingContext, IndependentLayoutResult,
NonReplacedFormattingContextContents,
IndependentNonReplacedContents,
};
use crate::fragment_tree::{
BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, FragmentFlags,
@ -2034,13 +2035,11 @@ impl IndependentFormattingContext {
match self.style().clone_baseline_source() {
BaselineSource::First => baselines.first,
BaselineSource::Last => baselines.last,
BaselineSource::Auto => {
if let Self::NonReplaced(non_replaced) = self {
if let NonReplacedFormattingContextContents::Flow(_) = non_replaced.contents {
return baselines.last;
}
}
baselines.first
BaselineSource::Auto => match &self.contents {
IndependentFormattingContextContents::NonReplaced(
IndependentNonReplacedContents::Flow(_),
) => baselines.last,
_ => baselines.first,
},
}
}

View file

@ -27,8 +27,8 @@ use crate::flow::float::{
SequentialLayoutState,
};
use crate::formatting_contexts::{
Baselines, IndependentFormattingContext, IndependentLayout, IndependentLayoutResult,
NonReplacedFormattingContext,
Baselines, IndependentFormattingContext, IndependentFormattingContextContents,
IndependentLayout, IndependentLayoutResult, IndependentNonReplacedContents,
};
use crate::fragment_tree::{
BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, FragmentFlags,
@ -37,8 +37,9 @@ use crate::geom::{
AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides,
Size, ToLogical, ToLogicalWithContainingBlock,
};
use crate::layout_box_base::LayoutBoxBase;
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength};
use crate::replaced::ReplacedContent;
use crate::replaced::ReplacedContents;
use crate::sizing::{self, ContentSizes, InlineContentSizesResult};
use crate::style_ext::{
Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated, PaddingBorderMargin,
@ -714,38 +715,20 @@ impl BlockLevelBox {
)
},
)),
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.base_fragment_info,
&replaced.style,
&replaced.contents,
sequential_layout_state,
)
},
))
},
IndependentFormattingContext::NonReplaced(non_replaced) => {
Fragment::Box(positioning_context.layout_maybe_position_relative_fragment(
layout_context,
containing_block,
&non_replaced.style,
|positioning_context| {
non_replaced.layout_in_flow_block_level(
layout_context,
positioning_context,
containing_block,
sequential_layout_state,
)
},
))
},
BlockLevelBox::Independent(independent) => {
Fragment::Box(positioning_context.layout_maybe_position_relative_fragment(
layout_context,
containing_block,
independent.style(),
|positioning_context| {
independent.layout_in_flow_block_level(
layout_context,
positioning_context,
containing_block,
sequential_layout_state,
)
},
))
},
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
// The static position of zero here is incorrect, however we do not know
@ -1006,7 +989,7 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
.with_baselines(flow_layout.baselines)
}
impl NonReplacedFormattingContext {
impl IndependentNonReplacedContents {
/// Lay out a normal in flow non-replaced block that establishes an independent
/// formatting context in its containing formatting context.
///
@ -1014,6 +997,7 @@ impl NonReplacedFormattingContext {
/// - <https://drafts.csswg.org/css2/visudet.html#normal-block>
pub(crate) fn layout_in_flow_block_level(
&self,
base: &LayoutBoxBase,
layout_context: &LayoutContext,
positioning_context: &mut PositioningContext,
containing_block: &ContainingBlock,
@ -1021,6 +1005,7 @@ impl NonReplacedFormattingContext {
) -> BoxFragment {
if let Some(sequential_layout_state) = sequential_layout_state {
return self.layout_in_flow_block_level_sequentially(
base,
layout_context,
positioning_context,
containing_block,
@ -1037,7 +1022,7 @@ impl NonReplacedFormattingContext {
depends_on_block_constraints,
} = solve_containing_block_padding_and_border_for_in_flow_box(
containing_block,
&self.style,
&base.style,
);
let layout = self.layout(
@ -1079,7 +1064,7 @@ impl NonReplacedFormattingContext {
let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
let containing_block_writing_mode = containing_block.style.writing_mode;
let mut base_fragment_info = self.base_fragment_info;
let mut base_fragment_info = base.base_fragment_info;
if depends_on_block_constraints {
base_fragment_info.flags.insert(
FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
@ -1087,7 +1072,7 @@ impl NonReplacedFormattingContext {
}
BoxFragment::new(
base_fragment_info,
self.style.clone(),
base.style.clone(),
layout.fragments,
content_rect.to_physical(Some(containing_block)),
pbm.padding.to_physical(containing_block_writing_mode),
@ -1104,6 +1089,7 @@ impl NonReplacedFormattingContext {
/// layout concerns, such clearing and placing the content next to floats.
fn layout_in_flow_block_level_sequentially(
&self,
base: &LayoutBoxBase,
layout_context: &LayoutContext<'_>,
positioning_context: &mut PositioningContext,
containing_block: &ContainingBlock<'_>,
@ -1116,7 +1102,7 @@ impl NonReplacedFormattingContext {
content_max_box_size,
pbm,
depends_on_block_constraints,
} = self
} = base
.style
.content_box_sizes_and_padding_border_margin(&containing_block.into())
.into();
@ -1147,6 +1133,7 @@ impl NonReplacedFormattingContext {
let clearance;
let mut content_size;
let mut layout;
let style = &base.style;
if let AuOrAuto::LengthPercentage(ref inline_size) = content_box_size.inline {
let inline_size = inline_size
.clamp_between_extremums(content_min_box_size.inline, content_max_box_size.inline);
@ -1156,7 +1143,7 @@ impl NonReplacedFormattingContext {
&ContainingBlock {
inline_size,
block_size,
style: &self.style,
style,
},
containing_block,
);
@ -1188,17 +1175,14 @@ impl NonReplacedFormattingContext {
containing_block,
&pbm,
content_size + pbm.padding_border_sums,
&self.style,
style,
);
} else {
// First compute the clear position required by the 'clear' property.
// The code below may then add extra clearance when the element can't fit
// next to floats not covered by 'clear'.
let clear_position = sequential_layout_state.calculate_clear_position(
Clear::from_style_and_container_writing_mode(
&self.style,
containing_block_writing_mode,
),
Clear::from_style_and_container_writing_mode(style, containing_block_writing_mode),
&collapsed_margin_block_start,
);
let ceiling = clear_position.unwrap_or_else(|| {
@ -1238,7 +1222,7 @@ impl NonReplacedFormattingContext {
&ContainingBlock {
inline_size: proposed_inline_size,
block_size,
style: &self.style,
style,
},
containing_block,
);
@ -1347,7 +1331,7 @@ impl NonReplacedFormattingContext {
size: content_size,
};
let mut base_fragment_info = self.base_fragment_info;
let mut base_fragment_info = base.base_fragment_info;
if depends_on_block_constraints {
base_fragment_info.flags.insert(
FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
@ -1356,7 +1340,7 @@ impl NonReplacedFormattingContext {
BoxFragment::new(
base_fragment_info,
self.style.clone(),
style.clone(),
layout.fragments,
content_rect.to_physical(Some(containing_block)),
pbm.padding.to_physical(containing_block_writing_mode),
@ -1369,121 +1353,127 @@ impl NonReplacedFormattingContext {
}
}
/// <https://drafts.csswg.org/css2/visudet.html#block-replaced-width>
/// <https://drafts.csswg.org/css2/visudet.html#inline-replaced-width>
/// <https://drafts.csswg.org/css2/visudet.html#inline-replaced-height>
fn layout_in_flow_replaced_block_level(
containing_block: &ContainingBlock,
mut base_fragment_info: BaseFragmentInfo,
style: &Arc<ComputedValues>,
replaced: &ReplacedContent,
mut sequential_layout_state: Option<&mut SequentialLayoutState>,
) -> BoxFragment {
let content_box_sizes_and_pbm =
style.content_box_sizes_and_padding_border_margin(&containing_block.into());
let pbm = &content_box_sizes_and_pbm.pbm;
let content_size = replaced.used_size_as_if_inline_element(
containing_block,
style,
&content_box_sizes_and_pbm,
);
let margin_inline_start;
let margin_inline_end;
let effective_margin_inline_start;
let (margin_block_start, margin_block_end) = solve_block_margins_for_in_flow_block_level(pbm);
let containing_block_writing_mode = containing_block.style.writing_mode;
let physical_content_size = content_size.to_physical_size(containing_block_writing_mode);
let fragments = replaced.make_fragments(style, physical_content_size);
let clearance;
if let Some(ref mut sequential_layout_state) = sequential_layout_state {
// From https://drafts.csswg.org/css2/#floats:
// "The border box of a table, a block-level replaced element, or an element in
// the normal flow that establishes a new block formatting context (such as an
// element with overflow other than visible) must not overlap the margin box of
// any floats in the same block formatting context as the element itself. If
// necessary, implementations should clear the said element by placing it below
// any preceding floats, but may place it adjacent to such floats if there is
// sufficient space. They may even make the border box of said element narrower
// than defined by section 10.3.3. CSS 2 does not define when a UA may put said
// element next to the float or by how much said element may become narrower."
let collapsed_margin_block_start = CollapsedMargin::new(margin_block_start);
let size = content_size + pbm.padding_border_sums;
(
clearance,
(margin_inline_start, margin_inline_end),
effective_margin_inline_start,
) = solve_clearance_and_inline_margins_avoiding_floats(
sequential_layout_state,
&collapsed_margin_block_start,
impl ReplacedContents {
/// <https://drafts.csswg.org/css2/visudet.html#block-replaced-width>
/// <https://drafts.csswg.org/css2/visudet.html#inline-replaced-width>
/// <https://drafts.csswg.org/css2/visudet.html#inline-replaced-height>
fn layout_in_flow_block_level(
&self,
base: &LayoutBoxBase,
containing_block: &ContainingBlock,
mut sequential_layout_state: Option<&mut SequentialLayoutState>,
) -> BoxFragment {
let content_box_sizes_and_pbm = base
.style
.content_box_sizes_and_padding_border_margin(&containing_block.into());
let pbm = &content_box_sizes_and_pbm.pbm;
let content_size = self.used_size_as_if_inline_element(
containing_block,
pbm,
size,
style,
&base.style,
&content_box_sizes_and_pbm,
);
// Clearance prevents margin collapse between this block and previous ones,
// so in that case collapse margins before adjoining them below.
if clearance.is_some() {
let margin_inline_start;
let margin_inline_end;
let effective_margin_inline_start;
let (margin_block_start, margin_block_end) =
solve_block_margins_for_in_flow_block_level(pbm);
let containing_block_writing_mode = containing_block.style.writing_mode;
let physical_content_size = content_size.to_physical_size(containing_block_writing_mode);
let fragments = self.make_fragments(&base.style, physical_content_size);
let clearance;
if let Some(ref mut sequential_layout_state) = sequential_layout_state {
// From https://drafts.csswg.org/css2/#floats:
// "The border box of a table, a block-level replaced element, or an element in
// the normal flow that establishes a new block formatting context (such as an
// element with overflow other than visible) must not overlap the margin box of
// any floats in the same block formatting context as the element itself. If
// necessary, implementations should clear the said element by placing it below
// any preceding floats, but may place it adjacent to such floats if there is
// sufficient space. They may even make the border box of said element narrower
// than defined by section 10.3.3. CSS 2 does not define when a UA may put said
// element next to the float or by how much said element may become narrower."
let collapsed_margin_block_start = CollapsedMargin::new(margin_block_start);
let size = content_size + pbm.padding_border_sums;
(
clearance,
(margin_inline_start, margin_inline_end),
effective_margin_inline_start,
) = solve_clearance_and_inline_margins_avoiding_floats(
sequential_layout_state,
&collapsed_margin_block_start,
containing_block,
pbm,
size,
&base.style,
);
// Clearance prevents margin collapse between this block and previous ones,
// so in that case collapse margins before adjoining them below.
if clearance.is_some() {
sequential_layout_state.collapse_margins();
}
sequential_layout_state.adjoin_assign(&collapsed_margin_block_start);
// Margins can never collapse into replaced elements.
sequential_layout_state.collapse_margins();
sequential_layout_state
.advance_block_position(size.block + clearance.unwrap_or_else(Au::zero));
sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin_block_end));
} else {
clearance = None;
(
(margin_inline_start, margin_inline_end),
effective_margin_inline_start,
) = solve_inline_margins_for_in_flow_block_level(
containing_block,
pbm,
content_size.inline,
);
};
let margin = LogicalSides {
inline_start: margin_inline_start,
inline_end: margin_inline_end,
block_start: margin_block_start,
block_end: margin_block_end,
};
let start_corner = LogicalVec2 {
block: pbm.padding.block_start +
pbm.border.block_start +
clearance.unwrap_or_else(Au::zero),
inline: pbm.padding.inline_start +
pbm.border.inline_start +
effective_margin_inline_start,
};
let content_rect = LogicalRect {
start_corner,
size: content_size,
}
sequential_layout_state.adjoin_assign(&collapsed_margin_block_start);
.to_physical(Some(containing_block));
// Margins can never collapse into replaced elements.
sequential_layout_state.collapse_margins();
sequential_layout_state
.advance_block_position(size.block + clearance.unwrap_or_else(Au::zero));
sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin_block_end));
} else {
clearance = None;
(
(margin_inline_start, margin_inline_end),
effective_margin_inline_start,
) = solve_inline_margins_for_in_flow_block_level(
containing_block,
pbm,
content_size.inline,
);
};
let mut base_fragment_info = base.base_fragment_info;
if content_box_sizes_and_pbm.depends_on_block_constraints {
base_fragment_info.flags.insert(
FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
);
}
let margin = LogicalSides {
inline_start: margin_inline_start,
inline_end: margin_inline_end,
block_start: margin_block_start,
block_end: margin_block_end,
};
let start_corner = LogicalVec2 {
block: pbm.padding.block_start +
pbm.border.block_start +
clearance.unwrap_or_else(Au::zero),
inline: pbm.padding.inline_start + pbm.border.inline_start + effective_margin_inline_start,
};
let content_rect = LogicalRect {
start_corner,
size: content_size,
BoxFragment::new(
base_fragment_info,
base.style.clone(),
fragments,
content_rect,
pbm.padding.to_physical(containing_block_writing_mode),
pbm.border.to_physical(containing_block_writing_mode),
margin.to_physical(containing_block_writing_mode),
clearance,
CollapsedBlockMargins::from_margin(&margin),
)
}
.to_physical(Some(containing_block));
if content_box_sizes_and_pbm.depends_on_block_constraints {
base_fragment_info
.flags
.insert(FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM);
}
BoxFragment::new(
base_fragment_info,
style.clone(),
fragments,
content_rect,
pbm.padding.to_physical(containing_block_writing_mode),
pbm.border.to_physical(containing_block_writing_mode),
margin.to_physical(containing_block_writing_mode),
clearance,
CollapsedBlockMargins::from_margin(&margin),
)
}
struct ContainingBlockPaddingAndBorder<'a> {
@ -2017,6 +2007,26 @@ fn block_size_is_zero_or_intrinsic(size: &StyleSize, containing_block: &Containi
}
impl IndependentFormattingContext {
pub(crate) fn layout_in_flow_block_level(
&self,
layout_context: &LayoutContext,
positioning_context: &mut PositioningContext,
containing_block: &ContainingBlock,
sequential_layout_state: Option<&mut SequentialLayoutState>,
) -> BoxFragment {
match &self.contents {
IndependentFormattingContextContents::NonReplaced(contents) => contents
.layout_in_flow_block_level(
&self.base,
layout_context,
positioning_context,
containing_block,
sequential_layout_state,
),
IndependentFormattingContextContents::Replaced(contents) => contents
.layout_in_flow_block_level(&self.base, containing_block, sequential_layout_state),
}
}
pub(crate) fn layout_float_or_atomic_inline(
&self,
layout_context: &LayoutContext,
@ -2031,27 +2041,24 @@ impl IndependentFormattingContext {
let margin = pbm.margin.auto_is(Au::zero);
let pbm_sums = pbm.padding + pbm.border + margin;
let (fragments, content_rect, baselines) = match self {
IndependentFormattingContext::Replaced(replaced) => {
let (fragments, content_rect, baselines) = match &self.contents {
IndependentFormattingContextContents::Replaced(replaced) => {
// https://drafts.csswg.org/css2/visudet.html#float-replaced-width
// https://drafts.csswg.org/css2/visudet.html#inline-replaced-height
let content_size = replaced
.contents
.used_size_as_if_inline_element(
containing_block,
&replaced.style,
style,
&content_box_sizes_and_pbm,
)
.to_physical_size(container_writing_mode);
let fragments = replaced
.contents
.make_fragments(&replaced.style, content_size);
let fragments = replaced.make_fragments(style, content_size);
let content_rect = PhysicalRect::new(PhysicalPoint::zero(), content_size);
(fragments, content_rect, None)
},
IndependentFormattingContext::NonReplaced(non_replaced) => {
let writing_mode = non_replaced.style.writing_mode;
IndependentFormattingContextContents::NonReplaced(non_replaced) => {
let writing_mode = self.style().writing_mode;
let available_inline_size =
(containing_block.inline_size - pbm_sums.inline_sum()).max(Au::zero());
let available_block_size = containing_block
@ -2110,7 +2117,7 @@ impl IndependentFormattingContext {
let containing_block_for_children = ContainingBlock {
inline_size,
block_size: tentative_block_size.to_auto_or(),
style: &non_replaced.style,
style: self.style(),
};
assert_eq!(
container_writing_mode.is_horizontal(),

View file

@ -28,7 +28,7 @@ use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragment_tree::FragmentTree;
use crate::geom::{LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize};
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
use crate::replaced::ReplacedContent;
use crate::replaced::ReplacedContents;
use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayInside};
use crate::taffy::{TaffyItemBox, TaffyItemBoxInner};
use crate::DefiniteContainingBlock;
@ -222,7 +222,7 @@ impl BoxTree {
loop {
if let Some((primary_style, display_inside, update_point)) = update_point(dirty_node) {
let contents = ReplacedContent::for_element(dirty_node, context)
let contents = ReplacedContents::for_element(dirty_node, context)
.map_or_else(|| NonReplacedContents::OfElement.into(), Contents::Replaced);
let info = NodeAndStyleInfo::new(dirty_node, Arc::clone(&primary_style));
let out_of_flow_absolutely_positioned_box = ArcRefCell::new(
@ -290,7 +290,7 @@ fn construct_for_root_element<'dom>(
Display::GeneratingBox(display_generating_box) => display_generating_box.display_inside(),
};
let contents = ReplacedContent::for_element(root_element, context)
let contents = ReplacedContents::for_element(root_element, context)
.map_or_else(|| NonReplacedContents::OfElement.into(), Contents::Replaced);
let root_box = if box_style.position.is_absolutely_positioned() {
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(ArcRefCell::new(

View file

@ -3,7 +3,6 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use app_units::Au;
use atomic_refcell::AtomicRefCell;
use serde::Serialize;
use servo_arc::Arc;
use style::properties::ComputedValues;
@ -17,46 +16,32 @@ use crate::flexbox::FlexContainer;
use crate::flow::BlockFormattingContext;
use crate::fragment_tree::{BaseFragmentInfo, BoxFragment, Fragment, FragmentFlags};
use crate::geom::LogicalSides;
use crate::layout_box_base::LayoutBoxBase;
use crate::positioned::PositioningContext;
use crate::replaced::ReplacedContent;
use crate::replaced::ReplacedContents;
use crate::sizing::{self, InlineContentSizesResult};
use crate::style_ext::{AspectRatio, DisplayInside};
use crate::table::Table;
use crate::taffy::TaffyContainer;
use crate::{
ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, LogicalVec2, SizeConstraint,
};
use crate::{ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, LogicalVec2};
/// <https://drafts.csswg.org/css-display/#independent-formatting-context>
#[derive(Debug, Serialize)]
pub(crate) enum IndependentFormattingContext {
NonReplaced(NonReplacedFormattingContext),
Replaced(ReplacedFormattingContext),
pub(crate) struct IndependentFormattingContext {
pub base: LayoutBoxBase,
pub contents: IndependentFormattingContextContents,
}
#[derive(Debug, Serialize)]
pub(crate) struct NonReplacedFormattingContext {
pub base_fragment_info: BaseFragmentInfo,
#[serde(skip_serializing)]
pub style: Arc<ComputedValues>,
/// If it was requested during construction
#[serde(skip_serializing)]
pub content_sizes_result: AtomicRefCell<Option<(SizeConstraint, InlineContentSizesResult)>>,
pub contents: NonReplacedFormattingContextContents,
}
#[derive(Debug, Serialize)]
pub(crate) struct ReplacedFormattingContext {
pub base_fragment_info: BaseFragmentInfo,
#[serde(skip_serializing)]
pub style: Arc<ComputedValues>,
pub contents: ReplacedContent,
pub(crate) enum IndependentFormattingContextContents {
NonReplaced(IndependentNonReplacedContents),
Replaced(ReplacedContents),
}
// Private so that code outside of this module cannot match variants.
// It should got through methods instead.
#[derive(Debug, Serialize)]
pub(crate) enum NonReplacedFormattingContextContents {
pub(crate) enum IndependentNonReplacedContents {
Flow(BlockFormattingContext),
Flex(FlexContainer),
Grid(TaffyContainer),
@ -115,24 +100,23 @@ impl IndependentFormattingContext {
contents: Contents,
propagated_text_decoration_line: TextDecorationLine,
) -> Self {
let mut base_fragment_info: BaseFragmentInfo = node_and_style_info.into();
match contents {
Contents::NonReplaced(non_replaced_contents) => {
let mut base_fragment_info: BaseFragmentInfo = node_and_style_info.into();
let contents = match display_inside {
DisplayInside::Flow { is_list_item } |
DisplayInside::FlowRoot { is_list_item } => {
NonReplacedFormattingContextContents::Flow(
BlockFormattingContext::construct(
context,
node_and_style_info,
non_replaced_contents,
propagated_text_decoration_line,
is_list_item,
),
)
IndependentNonReplacedContents::Flow(BlockFormattingContext::construct(
context,
node_and_style_info,
non_replaced_contents,
propagated_text_decoration_line,
is_list_item,
))
},
DisplayInside::Grid => {
NonReplacedFormattingContextContents::Grid(TaffyContainer::construct(
IndependentNonReplacedContents::Grid(TaffyContainer::construct(
context,
node_and_style_info,
non_replaced_contents,
@ -140,7 +124,7 @@ impl IndependentFormattingContext {
))
},
DisplayInside::Flex => {
NonReplacedFormattingContextContents::Flex(FlexContainer::construct(
IndependentNonReplacedContents::Flex(FlexContainer::construct(
context,
node_and_style_info,
non_replaced_contents,
@ -157,7 +141,7 @@ impl IndependentFormattingContext {
&node_and_style_info.style,
);
base_fragment_info.flags.insert(FragmentFlags::DO_NOT_PAINT);
NonReplacedFormattingContextContents::Table(Table::construct(
IndependentNonReplacedContents::Table(Table::construct(
context,
node_and_style_info,
table_grid_style,
@ -166,41 +150,36 @@ impl IndependentFormattingContext {
))
},
};
Self::NonReplaced(NonReplacedFormattingContext {
style: Arc::clone(&node_and_style_info.style),
base_fragment_info,
content_sizes_result: AtomicRefCell::default(),
contents,
})
Self {
base: LayoutBoxBase::new(base_fragment_info, node_and_style_info.style.clone()),
contents: IndependentFormattingContextContents::NonReplaced(contents),
}
},
Contents::Replaced(contents) => {
let mut base_fragment_info: BaseFragmentInfo = node_and_style_info.into();
base_fragment_info.flags.insert(FragmentFlags::IS_REPLACED);
Self::Replaced(ReplacedFormattingContext {
base_fragment_info,
style: Arc::clone(&node_and_style_info.style),
contents,
})
Self {
base: LayoutBoxBase::new(base_fragment_info, node_and_style_info.style.clone()),
contents: IndependentFormattingContextContents::Replaced(contents),
}
},
}
}
pub fn is_replaced(&self) -> bool {
matches!(self, Self::Replaced(_))
matches!(
self.contents,
IndependentFormattingContextContents::Replaced(_)
)
}
#[inline]
pub fn style(&self) -> &Arc<ComputedValues> {
match self {
Self::NonReplaced(inner) => &inner.style,
Self::Replaced(inner) => &inner.style,
}
&self.base.style
}
#[inline]
pub fn base_fragment_info(&self) -> BaseFragmentInfo {
match self {
Self::NonReplaced(inner) => inner.base_fragment_info,
Self::Replaced(inner) => inner.base_fragment_info,
}
self.base.base_fragment_info
}
pub(crate) fn inline_content_sizes(
@ -208,14 +187,15 @@ impl IndependentFormattingContext {
layout_context: &LayoutContext,
constraint_space: &ConstraintSpace,
) -> InlineContentSizesResult {
match self {
Self::NonReplaced(inner) => {
inner.inline_content_sizes(layout_context, constraint_space)
},
Self::Replaced(inner) => inner
.contents
.inline_content_sizes(layout_context, constraint_space),
}
self.base
.inline_content_sizes(constraint_space, || match &self.contents {
IndependentFormattingContextContents::NonReplaced(contents) => {
contents.inline_content_sizes(layout_context, constraint_space)
},
IndependentFormattingContextContents::Replaced(contents) => {
contents.inline_content_sizes(layout_context, constraint_space)
},
})
}
pub(crate) fn outer_inline_content_sizes(
@ -225,40 +205,32 @@ impl IndependentFormattingContext {
auto_minimum: &LogicalVec2<Au>,
auto_block_size_stretches_to_containing_block: bool,
) -> InlineContentSizesResult {
match self {
Self::NonReplaced(non_replaced) => non_replaced.outer_inline_content_sizes(
layout_context,
containing_block,
auto_minimum,
auto_block_size_stretches_to_containing_block,
),
Self::Replaced(replaced) => sizing::outer_inline(
&replaced.style,
containing_block,
auto_minimum,
auto_block_size_stretches_to_containing_block,
|padding_border_sums| replaced.preferred_aspect_ratio(padding_border_sums),
|constraint_space| {
replaced
.contents
.inline_content_sizes(layout_context, constraint_space)
},
),
}
sizing::outer_inline(
self.style(),
containing_block,
auto_minimum,
auto_block_size_stretches_to_containing_block,
|padding_border_sums| self.preferred_aspect_ratio(padding_border_sums),
|constraint_space| self.inline_content_sizes(layout_context, constraint_space),
)
}
pub(crate) fn preferred_aspect_ratio(
&self,
padding_border_sums: &LogicalVec2<Au>,
) -> Option<AspectRatio> {
match self {
Self::NonReplaced(non_replaced) => non_replaced.preferred_aspect_ratio(),
Self::Replaced(replaced) => replaced.preferred_aspect_ratio(padding_border_sums),
match &self.contents {
IndependentFormattingContextContents::NonReplaced(content) => {
content.preferred_aspect_ratio()
},
IndependentFormattingContextContents::Replaced(content) => {
content.preferred_aspect_ratio(self.style(), padding_border_sums)
},
}
}
}
impl NonReplacedFormattingContext {
impl IndependentNonReplacedContents {
pub fn layout(
&self,
layout_context: &LayoutContext,
@ -266,25 +238,25 @@ impl NonReplacedFormattingContext {
containing_block_for_children: &ContainingBlock,
containing_block: &ContainingBlock,
) -> IndependentLayout {
match &self.contents {
NonReplacedFormattingContextContents::Flow(bfc) => bfc.layout(
match self {
IndependentNonReplacedContents::Flow(bfc) => bfc.layout(
layout_context,
positioning_context,
containing_block_for_children,
),
NonReplacedFormattingContextContents::Flex(fc) => fc.layout(
IndependentNonReplacedContents::Flex(fc) => fc.layout(
layout_context,
positioning_context,
containing_block_for_children,
containing_block,
),
NonReplacedFormattingContextContents::Grid(fc) => fc.layout(
IndependentNonReplacedContents::Grid(fc) => fc.layout(
layout_context,
positioning_context,
containing_block_for_children,
containing_block,
),
NonReplacedFormattingContextContents::Table(table) => table.layout(
IndependentNonReplacedContents::Table(table) => table.layout(
layout_context,
positioning_context,
containing_block_for_children,
@ -299,47 +271,6 @@ impl NonReplacedFormattingContext {
None
}
pub(crate) fn inline_content_sizes(
&self,
layout_context: &LayoutContext,
constraint_space: &ConstraintSpace,
) -> InlineContentSizesResult {
let mut cache = self.content_sizes_result.borrow_mut();
if let Some((previous_cb_block_size, result)) = *cache {
if !result.depends_on_block_constraints ||
previous_cb_block_size == constraint_space.block_size
{
return result;
}
// TODO: Should we keep multiple caches for various block sizes?
}
let result = self
.contents
.inline_content_sizes(layout_context, constraint_space);
*cache = Some((constraint_space.block_size, result));
result
}
pub(crate) fn outer_inline_content_sizes(
&self,
layout_context: &LayoutContext,
containing_block: &IndefiniteContainingBlock,
auto_minimum: &LogicalVec2<Au>,
auto_block_size_stretches_to_containing_block: bool,
) -> InlineContentSizesResult {
sizing::outer_inline(
&self.style,
containing_block,
auto_minimum,
auto_block_size_stretches_to_containing_block,
|_| self.preferred_aspect_ratio(),
|constraint_space| self.inline_content_sizes(layout_context, constraint_space),
)
}
}
impl NonReplacedFormattingContextContents {
pub(crate) fn inline_content_sizes(
&self,
layout_context: &LayoutContext,
@ -355,13 +286,3 @@ impl NonReplacedFormattingContextContents {
}
}
}
impl ReplacedFormattingContext {
pub(crate) fn preferred_aspect_ratio(
&self,
padding_border_sums: &LogicalVec2<Au>,
) -> Option<AspectRatio> {
self.contents
.preferred_aspect_ratio(&self.style, padding_border_sums)
}
}

View file

@ -0,0 +1,61 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use atomic_refcell::AtomicRefCell;
use serde::Serialize;
use servo_arc::Arc;
use style::properties::ComputedValues;
use crate::fragment_tree::BaseFragmentInfo;
use crate::geom::SizeConstraint;
use crate::sizing::InlineContentSizesResult;
use crate::ConstraintSpace;
/// A box tree node that handles containing information about style and the original DOM
/// node or pseudo-element that it is based on. This also handles caching of layout values
/// such as the inline content sizes to avoid recalculating these values during layout
/// passes.
///
/// In the future, this will hold layout results to support incremental layout.
#[derive(Debug, Serialize)]
pub(crate) struct LayoutBoxBase {
pub base_fragment_info: BaseFragmentInfo,
#[serde(skip_serializing)]
pub style: Arc<ComputedValues>,
#[serde(skip_serializing)]
pub cached_inline_content_size:
AtomicRefCell<Option<(SizeConstraint, InlineContentSizesResult)>>,
}
impl LayoutBoxBase {
pub(crate) fn new(base_fragment_info: BaseFragmentInfo, style: Arc<ComputedValues>) -> Self {
Self {
base_fragment_info,
style,
cached_inline_content_size: AtomicRefCell::default(),
}
}
/// Get the inline content sizes of a box tree node that extends this [`LayoutBoxBase`], fetch
/// the result from a cache when possible.
pub(crate) fn inline_content_sizes(
&self,
constraint_space: &ConstraintSpace,
inline_content_sizes_fn: impl FnOnce() -> InlineContentSizesResult,
) -> InlineContentSizesResult {
let mut cache = self.cached_inline_content_size.borrow_mut();
if let Some((previous_cb_block_size, result)) = *cache {
if !result.depends_on_block_constraints ||
previous_cb_block_size == constraint_space.block_size
{
return result;
}
// TODO: Should we keep multiple caches for various block sizes?
}
let result = inline_content_sizes_fn();
*cache = Some((constraint_space.block_size, result));
result
}
}

View file

@ -14,6 +14,7 @@ pub mod flow;
mod formatting_contexts;
mod fragment_tree;
pub mod geom;
mod layout_box_base;
mod taffy;
#[macro_use]
pub mod layout_debug;

View file

@ -10,7 +10,7 @@ use style::values::computed::Image;
use crate::context::LayoutContext;
use crate::dom::NodeExt;
use crate::dom_traversal::{NodeAndStyleInfo, PseudoElementContentItem};
use crate::replaced::ReplacedContent;
use crate::replaced::ReplacedContents;
/// <https://drafts.csswg.org/css-lists/#content-property>
pub(crate) fn make_marker<'dom, Node>(
@ -32,7 +32,7 @@ where
// https://drafts.csswg.org/css-lists/#marker-image
let marker_image = || match &style.list_style_image {
Image::Url(url) => Some(vec![
PseudoElementContentItem::Replaced(ReplacedContent::from_image_url(
PseudoElementContentItem::Replaced(ReplacedContents::from_image_url(
node, context, url,
)?),
PseudoElementContentItem::Text(" ".into()),

View file

@ -20,7 +20,9 @@ use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
use crate::dom::NodeExt;
use crate::dom_traversal::{Contents, NodeAndStyleInfo};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::formatting_contexts::{
IndependentFormattingContext, IndependentFormattingContextContents,
};
use crate::fragment_tree::{
BoxFragment, CollapsedBlockMargins, Fragment, FragmentFlags, HoistedSharedFragment,
};
@ -521,24 +523,22 @@ impl HoistedAbsolutelyPositionedBox {
flip_anchor: false,
};
if let IndependentFormattingContext::Replaced(replaced) = context {
if let IndependentFormattingContextContents::Replaced(replaced) = &context.contents {
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
let inset_sums = LogicalVec2 {
inline: inline_axis_solver.inset_sum(),
block: block_axis_solver.inset_sum(),
};
let used_size = replaced
.contents
.used_size_as_if_inline_element_from_content_box_sizes(
containing_block,
&style,
replaced.preferred_aspect_ratio(&pbm.padding_border_sums),
computed_size,
computed_min_size,
computed_max_size,
pbm.padding_border_sums + pbm.margin.auto_is(Au::zero).sum() + inset_sums,
);
let used_size = replaced.used_size_as_if_inline_element_from_content_box_sizes(
containing_block,
&style,
context.preferred_aspect_ratio(&pbm.padding_border_sums),
computed_size,
computed_min_size,
computed_max_size,
pbm.padding_border_sums + pbm.margin.auto_is(Au::zero).sum() + inset_sums,
);
inline_axis_solver.override_size(used_size.inline);
block_axis_solver.override_size(used_size.block);
}
@ -561,20 +561,20 @@ impl HoistedAbsolutelyPositionedBox {
let mut new_fragment = {
let content_size: LogicalVec2<Au>;
let fragments;
match context {
IndependentFormattingContext::Replaced(replaced) => {
match &context.contents {
IndependentFormattingContextContents::Replaced(replaced) => {
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
content_size = LogicalVec2 {
inline: inline_axis.size.to_definite().unwrap(),
block: block_axis.size.to_definite().unwrap(),
};
fragments = replaced.contents.make_fragments(
fragments = replaced.make_fragments(
&style,
content_size.to_physical_size(containing_block_writing_mode),
);
},
IndependentFormattingContext::NonReplaced(non_replaced) => {
IndependentFormattingContextContents::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.to_definite().unwrap();

View file

@ -34,7 +34,7 @@ use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAnd
use crate::{ConstraintSpace, ContainingBlock, SizeConstraint};
#[derive(Debug, Serialize)]
pub(crate) struct ReplacedContent {
pub(crate) struct ReplacedContents {
pub kind: ReplacedContentKind,
natural_size: NaturalSizes,
base_fragment_info: BaseFragmentInfo,
@ -140,7 +140,7 @@ pub(crate) enum ReplacedContentKind {
Video(Option<VideoInfo>),
}
impl ReplacedContent {
impl ReplacedContents {
pub fn for_element<'dom>(element: impl NodeExt<'dom>, context: &LayoutContext) -> Option<Self> {
if let Some(ref data_attribute_string) = element.as_typeless_object_with_data_attribute() {
if let Some(url) = try_to_parse_image_data_url(data_attribute_string) {

View file

@ -25,10 +25,11 @@ use crate::dom::{BoxSlot, NodeExt};
use crate::dom_traversal::{Contents, NodeAndStyleInfo, NonReplacedContents, TraversalHandler};
use crate::flow::{BlockContainerBuilder, BlockFormattingContext};
use crate::formatting_contexts::{
IndependentFormattingContext, NonReplacedFormattingContext,
NonReplacedFormattingContextContents,
IndependentFormattingContext, IndependentFormattingContextContents,
IndependentNonReplacedContents,
};
use crate::fragment_tree::BaseFragmentInfo;
use crate::layout_box_base::LayoutBoxBase;
use crate::style_ext::{DisplayGeneratingBox, DisplayLayoutInternal};
/// A reference to a slot and its coordinates in the table
@ -134,12 +135,12 @@ impl Table {
let mut table = table_builder.finish();
table.anonymous = true;
IndependentFormattingContext::NonReplaced(NonReplacedFormattingContext {
base_fragment_info: (&anonymous_info).into(),
style: grid_and_wrapper_style,
content_sizes_result: Default::default(),
contents: NonReplacedFormattingContextContents::Table(table),
})
IndependentFormattingContext {
base: LayoutBoxBase::new((&anonymous_info).into(), grid_and_wrapper_style),
contents: IndependentFormattingContextContents::NonReplaced(
IndependentNonReplacedContents::Table(table),
),
}
}
/// Push a new slot into the last row of this table.
@ -853,15 +854,13 @@ where
DisplayLayoutInternal::TableCaption => {
let contents = match contents.try_into() {
Ok(non_replaced_contents) => {
NonReplacedFormattingContextContents::Flow(
BlockFormattingContext::construct(
self.context,
info,
non_replaced_contents,
self.current_text_decoration_line,
false, /* is_list_item */
),
)
IndependentNonReplacedContents::Flow(BlockFormattingContext::construct(
self.context,
info,
non_replaced_contents,
self.current_text_decoration_line,
false, /* is_list_item */
))
},
Err(_replaced) => {
unreachable!("Replaced should not have a LayoutInternal display type.");
@ -869,11 +868,9 @@ where
};
let caption = TableCaption {
context: ArcRefCell::new(NonReplacedFormattingContext {
style: info.style.clone(),
base_fragment_info: info.into(),
content_sizes_result: Default::default(),
contents,
context: ArcRefCell::new(IndependentFormattingContext {
base: LayoutBoxBase::new(info.into(), info.style.clone()),
contents: IndependentFormattingContextContents::NonReplaced(contents),
}),
};

View file

@ -1613,7 +1613,7 @@ impl<'a> TableLayout<'a> {
parent_positioning_context: &mut PositioningContext,
) -> BoxFragment {
let context = caption.context.borrow();
let mut positioning_context = PositioningContext::new_for_style(&context.style);
let mut positioning_context = PositioningContext::new_for_style(context.style());
let containing_block = &ContainingBlock {
inline_size: self.table_width + table_pbm.padding_border_sums.inline,
block_size: AuOrAuto::Auto,
@ -1711,7 +1711,7 @@ impl<'a> TableLayout<'a> {
table_layout
.fragments
.extend(self.table.captions.iter().filter_map(|caption| {
if caption.context.borrow().style.clone_caption_side() != CaptionSide::Top {
if caption.context.borrow().style().clone_caption_side() != CaptionSide::Top {
return None;
}
@ -1811,7 +1811,7 @@ impl<'a> TableLayout<'a> {
table_layout
.fragments
.extend(self.table.captions.iter().filter_map(|caption| {
if caption.context.borrow().style.clone_caption_side() != CaptionSide::Bottom {
if caption.context.borrow().style().clone_caption_side() != CaptionSide::Bottom {
return None;
}

View file

@ -82,7 +82,7 @@ use style_traits::dom::OpaqueNode;
use super::flow::BlockFormattingContext;
use crate::cell::ArcRefCell;
use crate::flow::BlockContainer;
use crate::formatting_contexts::NonReplacedFormattingContext;
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragment_tree::BaseFragmentInfo;
pub type TableSize = Size2D<usize, UnknownUnit>;
@ -320,5 +320,5 @@ impl TableTrackGroup {
#[derive(Debug, Serialize)]
pub struct TableCaption {
/// The contents of this cell, with its own layout.
context: ArcRefCell<NonReplacedFormattingContext>,
context: ArcRefCell<IndependentFormattingContext>,
}

View file

@ -15,7 +15,10 @@ use taffy::{AvailableSpace, MaybeMath, RequestedAxis, RunMode};
use super::{TaffyContainer, TaffyItemBox, TaffyItemBoxInner, TaffyStyloStyle};
use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
use crate::formatting_contexts::{Baselines, IndependentFormattingContext, IndependentLayout};
use crate::formatting_contexts::{
Baselines, IndependentFormattingContext, IndependentFormattingContextContents,
IndependentLayout,
};
use crate::fragment_tree::{BoxFragment, CollapsedBlockMargins, Fragment};
use crate::geom::{
LogicalSides, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalSize, Size,
@ -43,13 +46,12 @@ fn resolve_content_size(constraint: AvailableSpace, content_sizes: ContentSizes)
#[inline(always)]
fn with_independant_formatting_context<T>(
item: &mut TaffyItemBoxInner,
cb: impl FnOnce(&mut IndependentFormattingContext) -> T,
cb: impl FnOnce(&IndependentFormattingContext) -> T,
) -> T {
match item {
TaffyItemBoxInner::InFlowBox(ref mut context) => cb(context),
TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(ref abspos_box) => {
let mut abspos_box = AtomicRefCell::borrow_mut(abspos_box);
cb(&mut abspos_box.context)
cb(&AtomicRefCell::borrow(abspos_box).context)
},
}
}
@ -132,13 +134,14 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> {
with_independant_formatting_context(
&mut child.taffy_level_box,
|independent_context| -> taffy::LayoutOutput {
match independent_context {
IndependentFormattingContext::Replaced(replaced) => {
let style = independent_context.style();
match &independent_context.contents {
IndependentFormattingContextContents::Replaced(replaced) => {
// TODO: re-evaluate sizing constraint conversions in light of recent layout_2020 changes
let containing_block = &self.content_box_size_override;
// Adjust known_dimensions from border box to content box
let pbm = replaced.style.padding_border_margin(containing_block);
let pbm = style.padding_border_margin(containing_block);
let pb_sum = pbm.padding_border_sums.map(|v| v.to_f32_px());
let content_box_known_dimensions = taffy::Size {
width: inputs
@ -152,11 +155,11 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> {
};
let content_box_size = replaced
.contents
.used_size_as_if_inline_element_from_content_box_sizes(
containing_block,
&replaced.style,
replaced.preferred_aspect_ratio(&pbm.padding_border_sums),
style,
independent_context
.preferred_aspect_ratio(&pbm.padding_border_sums),
LogicalVec2 {
inline: option_f32_to_size(content_box_known_dimensions.width),
block: option_f32_to_size(content_box_known_dimensions.height),
@ -176,9 +179,8 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> {
// Create fragments if the RunMode if PerformLayout
// If the RunMode is ComputeSize then only the returned size will be used
if inputs.run_mode == RunMode::PerformLayout {
child.child_fragments = replaced
.contents
.make_fragments(&replaced.style, content_box_size);
child.child_fragments =
replaced.make_fragments(style, content_box_size);
}
let computed_size = taffy::Size {
@ -198,12 +200,12 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> {
}
},
IndependentFormattingContext::NonReplaced(non_replaced) => {
IndependentFormattingContextContents::NonReplaced(non_replaced) => {
// TODO: re-evaluate sizing constraint conversions in light of recent layout_2020 changes
let containing_block = &self.content_box_size_override;
// Adjust known_dimensions from border box to content box
let pbm = non_replaced.style.padding_border_margin(containing_block);
let pbm = style.padding_border_margin(containing_block);
let margin_sum = pbm.margin.auto_is(Au::zero).sum();
let content_box_inset =
(pbm.padding_border_sums + margin_sum).map(|v| v.to_f32_px());
@ -256,7 +258,7 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> {
let content_box_size_override = ContainingBlock {
inline_size: Au::from_f32_px(inline_size),
block_size: maybe_block_size,
style: &non_replaced.style,
style,
};
let layout = {