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

View file

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

View file

@ -30,7 +30,9 @@ use super::{
}; };
use crate::cell::ArcRefCell; use crate::cell::ArcRefCell;
use crate::context::LayoutContext; 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::fragment_tree::{BoxFragment, CollapsedBlockMargins, Fragment, FragmentFlags};
use crate::geom::{AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, Size}; use crate::geom::{AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, Size};
use crate::positioned::{ use crate::positioned::{
@ -1893,8 +1895,8 @@ impl FlexItem<'_> {
}), }),
}; };
let context = &self.box_.independent_formatting_context; let independent_formatting_context = &self.box_.independent_formatting_context;
let item_writing_mode = context.style().writing_mode; let item_writing_mode = independent_formatting_context.style().writing_mode;
let item_is_horizontal = item_writing_mode.is_horizontal(); let item_is_horizontal = item_writing_mode.is_horizontal();
let flex_axis = flex_context.config.flex_axis; let flex_axis = flex_context.config.flex_axis;
let cross_axis_is_item_block_axis = cross_axis_is_item_block_axis( let cross_axis_is_item_block_axis = cross_axis_is_item_block_axis(
@ -1922,7 +1924,7 @@ impl FlexItem<'_> {
item_writing_mode, item_writing_mode,
self.preferred_aspect_ratio, self.preferred_aspect_ratio,
); );
context independent_formatting_context
.inline_content_sizes(flex_context.layout_context, &constraint_space) .inline_content_sizes(flex_context.layout_context, &constraint_space)
.sizes .sizes
.shrink_to_fit(stretch_size) .shrink_to_fit(stretch_size)
@ -1945,13 +1947,12 @@ impl FlexItem<'_> {
}; };
let container_writing_mode = containing_block.style.writing_mode; let container_writing_mode = containing_block.style.writing_mode;
match context { let item_style = independent_formatting_context.style();
IndependentFormattingContext::Replaced(replaced) => { match &independent_formatting_context.contents {
let size = replaced IndependentFormattingContextContents::Replaced(replaced) => {
.contents let size = replaced.used_size_as_if_inline_element_from_content_box_sizes(
.used_size_as_if_inline_element_from_content_box_sizes(
containing_block, containing_block,
&replaced.style, item_style,
self.preferred_aspect_ratio, self.preferred_aspect_ratio,
LogicalVec2 { LogicalVec2 {
inline: Size::Numeric(inline_size), inline: Size::Numeric(inline_size),
@ -1979,10 +1980,8 @@ impl FlexItem<'_> {
} }
} }
let fragments = replaced.contents.make_fragments( let fragments = replaced
&replaced.style, .make_fragments(item_style, size.to_physical_size(container_writing_mode));
size.to_physical_size(container_writing_mode),
);
Some(FlexItemLayoutResult { Some(FlexItemLayoutResult {
hypothetical_cross_size, hypothetical_cross_size,
@ -2000,7 +1999,7 @@ impl FlexItem<'_> {
baseline_relative_to_margin_box: None, baseline_relative_to_margin_box: None,
}) })
}, },
IndependentFormattingContext::NonReplaced(non_replaced) => { IndependentFormattingContextContents::NonReplaced(non_replaced) => {
let calculate_hypothetical_cross_size = |content_block_size| { let calculate_hypothetical_cross_size = |content_block_size| {
self.content_box_size self.content_box_size
.cross .cross
@ -2020,7 +2019,7 @@ impl FlexItem<'_> {
let item_as_containing_block = ContainingBlock { let item_as_containing_block = ContainingBlock {
inline_size, inline_size,
block_size, block_size,
style: &non_replaced.style, style: item_style,
}; };
if let Some(non_stretch_layout_result) = non_stretch_layout_result { 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 = let item_writing_mode_is_orthogonal_to_container_writing_mode =
flex_context.config.writing_mode.is_horizontal() != 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 { let has_compatible_baseline = match flex_axis {
FlexAxis::Row => !item_writing_mode_is_orthogonal_to_container_writing_mode, FlexAxis::Row => !item_writing_mode_is_orthogonal_to_container_writing_mode,
FlexAxis::Column => 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(), .collects_for_nearest_positioned_ancestor(),
); );
match &self.independent_formatting_context { let style = self.independent_formatting_context.style();
IndependentFormattingContext::Replaced(replaced) => { match &self.independent_formatting_context.contents {
IndependentFormattingContextContents::Replaced(replaced) => {
content_box_size.inline = content_box_size.inline.map(|v| v.max(Au::zero())); content_box_size.inline = content_box_size.inline.map(|v| v.max(Au::zero()));
if intrinsic_sizing_mode == IntrinsicSizingMode::Size { if intrinsic_sizing_mode == IntrinsicSizingMode::Size {
content_box_size.block = AuOrAuto::Auto; content_box_size.block = AuOrAuto::Auto;
@ -2761,10 +2761,9 @@ impl FlexItemBox {
max_size.block = None; max_size.block = None;
} }
replaced replaced
.contents
.used_size_as_if_inline_element_from_content_box_sizes( .used_size_as_if_inline_element_from_content_box_sizes(
flex_context.containing_block, flex_context.containing_block,
&replaced.style, style,
preferred_aspect_ratio, preferred_aspect_ratio,
content_box_size content_box_size
.map(|size| size.non_auto().map_or(Size::Initial, Size::Numeric)), .map(|size| size.non_auto().map_or(Size::Initial, Size::Numeric)),
@ -2775,7 +2774,7 @@ impl FlexItemBox {
) )
.block .block
}, },
IndependentFormattingContext::NonReplaced(non_replaced) => { IndependentFormattingContextContents::NonReplaced(non_replaced) => {
// TODO: This is wrong if the item writing mode is different from the flex // TODO: This is wrong if the item writing mode is different from the flex
// container's writing mode. // container's writing mode.
let inline_size = content_box_size let inline_size = content_box_size
@ -2792,7 +2791,7 @@ impl FlexItemBox {
} else { } else {
let constraint_space = ConstraintSpace::new( let constraint_space = ConstraintSpace::new(
SizeConstraint::default(), SizeConstraint::default(),
non_replaced.style.writing_mode, style.writing_mode,
non_replaced.preferred_aspect_ratio(), non_replaced.preferred_aspect_ratio(),
); );
non_replaced non_replaced
@ -2808,7 +2807,7 @@ impl FlexItemBox {
let item_as_containing_block = ContainingBlock { let item_as_containing_block = ContainingBlock {
inline_size, inline_size,
block_size: AuOrAuto::Auto, block_size: AuOrAuto::Auto,
style: &non_replaced.style, style,
}; };
let content_block_size = || { let content_block_size = || {
if let Some(cache) = &*self.block_content_size_cache.borrow() { 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 xi_unicode::linebreak_property;
use super::float::{Clear, PlacementAmongFloats}; use super::float::{Clear, PlacementAmongFloats};
use super::IndependentFormattingContextContents;
use crate::cell::ArcRefCell; use crate::cell::ArcRefCell;
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::flow::float::{FloatBox, SequentialLayoutState}; use crate::flow::float::{FloatBox, SequentialLayoutState};
use crate::flow::{CollapsibleWithParentStartMargin, FlowLayout}; use crate::flow::{CollapsibleWithParentStartMargin, FlowLayout};
use crate::formatting_contexts::{ use crate::formatting_contexts::{
Baselines, IndependentFormattingContext, IndependentLayoutResult, Baselines, IndependentFormattingContext, IndependentLayoutResult,
NonReplacedFormattingContextContents, IndependentNonReplacedContents,
}; };
use crate::fragment_tree::{ use crate::fragment_tree::{
BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, FragmentFlags, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, FragmentFlags,
@ -2034,13 +2035,11 @@ impl IndependentFormattingContext {
match self.style().clone_baseline_source() { match self.style().clone_baseline_source() {
BaselineSource::First => baselines.first, BaselineSource::First => baselines.first,
BaselineSource::Last => baselines.last, BaselineSource::Last => baselines.last,
BaselineSource::Auto => { BaselineSource::Auto => match &self.contents {
if let Self::NonReplaced(non_replaced) = self { IndependentFormattingContextContents::NonReplaced(
if let NonReplacedFormattingContextContents::Flow(_) = non_replaced.contents { IndependentNonReplacedContents::Flow(_),
return baselines.last; ) => baselines.last,
} _ => baselines.first,
}
baselines.first
}, },
} }
} }

View file

@ -27,8 +27,8 @@ use crate::flow::float::{
SequentialLayoutState, SequentialLayoutState,
}; };
use crate::formatting_contexts::{ use crate::formatting_contexts::{
Baselines, IndependentFormattingContext, IndependentLayout, IndependentLayoutResult, Baselines, IndependentFormattingContext, IndependentFormattingContextContents,
NonReplacedFormattingContext, IndependentLayout, IndependentLayoutResult, IndependentNonReplacedContents,
}; };
use crate::fragment_tree::{ use crate::fragment_tree::{
BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, FragmentFlags, BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, FragmentFlags,
@ -37,8 +37,9 @@ use crate::geom::{
AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides, AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides,
Size, ToLogical, ToLogicalWithContainingBlock, Size, ToLogical, ToLogicalWithContainingBlock,
}; };
use crate::layout_box_base::LayoutBoxBase;
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength}; use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength};
use crate::replaced::ReplacedContent; use crate::replaced::ReplacedContents;
use crate::sizing::{self, ContentSizes, InlineContentSizesResult}; use crate::sizing::{self, ContentSizes, InlineContentSizesResult};
use crate::style_ext::{ use crate::style_ext::{
Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated, PaddingBorderMargin, Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated, PaddingBorderMargin,
@ -714,30 +715,13 @@ impl BlockLevelBox {
) )
}, },
)), )),
BlockLevelBox::Independent(independent) => match independent { BlockLevelBox::Independent(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,
&replaced.style, independent.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| { |positioning_context| {
non_replaced.layout_in_flow_block_level( independent.layout_in_flow_block_level(
layout_context, layout_context,
positioning_context, positioning_context,
containing_block, containing_block,
@ -746,7 +730,6 @@ impl BlockLevelBox {
}, },
)) ))
}, },
},
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => { BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
// The static position of zero here is incorrect, however we do not know // The static position of zero here is incorrect, however we do not know
// the correct positioning until later, in place_block_level_fragment, and // the correct positioning until later, in place_block_level_fragment, and
@ -1006,7 +989,7 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
.with_baselines(flow_layout.baselines) .with_baselines(flow_layout.baselines)
} }
impl NonReplacedFormattingContext { impl IndependentNonReplacedContents {
/// Lay out a normal in flow non-replaced block that establishes an independent /// Lay out a normal in flow non-replaced block that establishes an independent
/// formatting context in its containing formatting context. /// formatting context in its containing formatting context.
/// ///
@ -1014,6 +997,7 @@ impl NonReplacedFormattingContext {
/// - <https://drafts.csswg.org/css2/visudet.html#normal-block> /// - <https://drafts.csswg.org/css2/visudet.html#normal-block>
pub(crate) fn layout_in_flow_block_level( pub(crate) fn layout_in_flow_block_level(
&self, &self,
base: &LayoutBoxBase,
layout_context: &LayoutContext, layout_context: &LayoutContext,
positioning_context: &mut PositioningContext, positioning_context: &mut PositioningContext,
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
@ -1021,6 +1005,7 @@ impl NonReplacedFormattingContext {
) -> BoxFragment { ) -> BoxFragment {
if let Some(sequential_layout_state) = sequential_layout_state { if let Some(sequential_layout_state) = sequential_layout_state {
return self.layout_in_flow_block_level_sequentially( return self.layout_in_flow_block_level_sequentially(
base,
layout_context, layout_context,
positioning_context, positioning_context,
containing_block, containing_block,
@ -1037,7 +1022,7 @@ impl NonReplacedFormattingContext {
depends_on_block_constraints, depends_on_block_constraints,
} = solve_containing_block_padding_and_border_for_in_flow_box( } = solve_containing_block_padding_and_border_for_in_flow_box(
containing_block, containing_block,
&self.style, &base.style,
); );
let layout = self.layout( let layout = self.layout(
@ -1079,7 +1064,7 @@ impl NonReplacedFormattingContext {
let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin); let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
let containing_block_writing_mode = containing_block.style.writing_mode; 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 { if depends_on_block_constraints {
base_fragment_info.flags.insert( base_fragment_info.flags.insert(
FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM, FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
@ -1087,7 +1072,7 @@ impl NonReplacedFormattingContext {
} }
BoxFragment::new( BoxFragment::new(
base_fragment_info, base_fragment_info,
self.style.clone(), base.style.clone(),
layout.fragments, layout.fragments,
content_rect.to_physical(Some(containing_block)), content_rect.to_physical(Some(containing_block)),
pbm.padding.to_physical(containing_block_writing_mode), 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. /// layout concerns, such clearing and placing the content next to floats.
fn layout_in_flow_block_level_sequentially( fn layout_in_flow_block_level_sequentially(
&self, &self,
base: &LayoutBoxBase,
layout_context: &LayoutContext<'_>, layout_context: &LayoutContext<'_>,
positioning_context: &mut PositioningContext, positioning_context: &mut PositioningContext,
containing_block: &ContainingBlock<'_>, containing_block: &ContainingBlock<'_>,
@ -1116,7 +1102,7 @@ impl NonReplacedFormattingContext {
content_max_box_size, content_max_box_size,
pbm, pbm,
depends_on_block_constraints, depends_on_block_constraints,
} = self } = base
.style .style
.content_box_sizes_and_padding_border_margin(&containing_block.into()) .content_box_sizes_and_padding_border_margin(&containing_block.into())
.into(); .into();
@ -1147,6 +1133,7 @@ impl NonReplacedFormattingContext {
let clearance; let clearance;
let mut content_size; let mut content_size;
let mut layout; let mut layout;
let style = &base.style;
if let AuOrAuto::LengthPercentage(ref inline_size) = content_box_size.inline { if let AuOrAuto::LengthPercentage(ref inline_size) = content_box_size.inline {
let inline_size = inline_size let inline_size = inline_size
.clamp_between_extremums(content_min_box_size.inline, content_max_box_size.inline); .clamp_between_extremums(content_min_box_size.inline, content_max_box_size.inline);
@ -1156,7 +1143,7 @@ impl NonReplacedFormattingContext {
&ContainingBlock { &ContainingBlock {
inline_size, inline_size,
block_size, block_size,
style: &self.style, style,
}, },
containing_block, containing_block,
); );
@ -1188,17 +1175,14 @@ impl NonReplacedFormattingContext {
containing_block, containing_block,
&pbm, &pbm,
content_size + pbm.padding_border_sums, content_size + pbm.padding_border_sums,
&self.style, style,
); );
} else { } else {
// First compute the clear position required by the 'clear' property. // First compute the clear position required by the 'clear' property.
// The code below may then add extra clearance when the element can't fit // The code below may then add extra clearance when the element can't fit
// next to floats not covered by 'clear'. // next to floats not covered by 'clear'.
let clear_position = sequential_layout_state.calculate_clear_position( let clear_position = sequential_layout_state.calculate_clear_position(
Clear::from_style_and_container_writing_mode( Clear::from_style_and_container_writing_mode(style, containing_block_writing_mode),
&self.style,
containing_block_writing_mode,
),
&collapsed_margin_block_start, &collapsed_margin_block_start,
); );
let ceiling = clear_position.unwrap_or_else(|| { let ceiling = clear_position.unwrap_or_else(|| {
@ -1238,7 +1222,7 @@ impl NonReplacedFormattingContext {
&ContainingBlock { &ContainingBlock {
inline_size: proposed_inline_size, inline_size: proposed_inline_size,
block_size, block_size,
style: &self.style, style,
}, },
containing_block, containing_block,
); );
@ -1347,7 +1331,7 @@ impl NonReplacedFormattingContext {
size: content_size, 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 { if depends_on_block_constraints {
base_fragment_info.flags.insert( base_fragment_info.flags.insert(
FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM, FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
@ -1356,7 +1340,7 @@ impl NonReplacedFormattingContext {
BoxFragment::new( BoxFragment::new(
base_fragment_info, base_fragment_info,
self.style.clone(), style.clone(),
layout.fragments, layout.fragments,
content_rect.to_physical(Some(containing_block)), content_rect.to_physical(Some(containing_block)),
pbm.padding.to_physical(containing_block_writing_mode), pbm.padding.to_physical(containing_block_writing_mode),
@ -1369,33 +1353,35 @@ impl NonReplacedFormattingContext {
} }
} }
/// <https://drafts.csswg.org/css2/visudet.html#block-replaced-width> impl ReplacedContents {
/// <https://drafts.csswg.org/css2/visudet.html#inline-replaced-width> /// <https://drafts.csswg.org/css2/visudet.html#block-replaced-width>
/// <https://drafts.csswg.org/css2/visudet.html#inline-replaced-height> /// <https://drafts.csswg.org/css2/visudet.html#inline-replaced-width>
fn layout_in_flow_replaced_block_level( /// <https://drafts.csswg.org/css2/visudet.html#inline-replaced-height>
fn layout_in_flow_block_level(
&self,
base: &LayoutBoxBase,
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
mut base_fragment_info: BaseFragmentInfo,
style: &Arc<ComputedValues>,
replaced: &ReplacedContent,
mut sequential_layout_state: Option<&mut SequentialLayoutState>, mut sequential_layout_state: Option<&mut SequentialLayoutState>,
) -> BoxFragment { ) -> BoxFragment {
let content_box_sizes_and_pbm = let content_box_sizes_and_pbm = base
style.content_box_sizes_and_padding_border_margin(&containing_block.into()); .style
.content_box_sizes_and_padding_border_margin(&containing_block.into());
let pbm = &content_box_sizes_and_pbm.pbm; let pbm = &content_box_sizes_and_pbm.pbm;
let content_size = replaced.used_size_as_if_inline_element( let content_size = self.used_size_as_if_inline_element(
containing_block, containing_block,
style, &base.style,
&content_box_sizes_and_pbm, &content_box_sizes_and_pbm,
); );
let margin_inline_start; let margin_inline_start;
let margin_inline_end; let margin_inline_end;
let effective_margin_inline_start; let effective_margin_inline_start;
let (margin_block_start, margin_block_end) = solve_block_margins_for_in_flow_block_level(pbm); 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 containing_block_writing_mode = containing_block.style.writing_mode;
let physical_content_size = content_size.to_physical_size(containing_block_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 fragments = self.make_fragments(&base.style, physical_content_size);
let clearance; let clearance;
if let Some(ref mut sequential_layout_state) = sequential_layout_state { if let Some(ref mut sequential_layout_state) = sequential_layout_state {
@ -1421,7 +1407,7 @@ fn layout_in_flow_replaced_block_level(
containing_block, containing_block,
pbm, pbm,
size, size,
style, &base.style,
); );
// Clearance prevents margin collapse between this block and previous ones, // Clearance prevents margin collapse between this block and previous ones,
@ -1459,7 +1445,9 @@ fn layout_in_flow_replaced_block_level(
block: pbm.padding.block_start + block: pbm.padding.block_start +
pbm.border.block_start + pbm.border.block_start +
clearance.unwrap_or_else(Au::zero), clearance.unwrap_or_else(Au::zero),
inline: pbm.padding.inline_start + pbm.border.inline_start + effective_margin_inline_start, inline: pbm.padding.inline_start +
pbm.border.inline_start +
effective_margin_inline_start,
}; };
let content_rect = LogicalRect { let content_rect = LogicalRect {
start_corner, start_corner,
@ -1467,15 +1455,16 @@ fn layout_in_flow_replaced_block_level(
} }
.to_physical(Some(containing_block)); .to_physical(Some(containing_block));
let mut base_fragment_info = base.base_fragment_info;
if content_box_sizes_and_pbm.depends_on_block_constraints { if content_box_sizes_and_pbm.depends_on_block_constraints {
base_fragment_info base_fragment_info.flags.insert(
.flags FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
.insert(FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM); );
} }
BoxFragment::new( BoxFragment::new(
base_fragment_info, base_fragment_info,
style.clone(), base.style.clone(),
fragments, fragments,
content_rect, content_rect,
pbm.padding.to_physical(containing_block_writing_mode), pbm.padding.to_physical(containing_block_writing_mode),
@ -1484,6 +1473,7 @@ fn layout_in_flow_replaced_block_level(
clearance, clearance,
CollapsedBlockMargins::from_margin(&margin), CollapsedBlockMargins::from_margin(&margin),
) )
}
} }
struct ContainingBlockPaddingAndBorder<'a> { struct ContainingBlockPaddingAndBorder<'a> {
@ -2017,6 +2007,26 @@ fn block_size_is_zero_or_intrinsic(size: &StyleSize, containing_block: &Containi
} }
impl IndependentFormattingContext { 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( pub(crate) fn layout_float_or_atomic_inline(
&self, &self,
layout_context: &LayoutContext, layout_context: &LayoutContext,
@ -2031,27 +2041,24 @@ impl IndependentFormattingContext {
let margin = pbm.margin.auto_is(Au::zero); let margin = pbm.margin.auto_is(Au::zero);
let pbm_sums = pbm.padding + pbm.border + margin; let pbm_sums = pbm.padding + pbm.border + margin;
let (fragments, content_rect, baselines) = match self { let (fragments, content_rect, baselines) = match &self.contents {
IndependentFormattingContext::Replaced(replaced) => { IndependentFormattingContextContents::Replaced(replaced) => {
// https://drafts.csswg.org/css2/visudet.html#float-replaced-width // https://drafts.csswg.org/css2/visudet.html#float-replaced-width
// https://drafts.csswg.org/css2/visudet.html#inline-replaced-height // https://drafts.csswg.org/css2/visudet.html#inline-replaced-height
let content_size = replaced let content_size = replaced
.contents
.used_size_as_if_inline_element( .used_size_as_if_inline_element(
containing_block, containing_block,
&replaced.style, style,
&content_box_sizes_and_pbm, &content_box_sizes_and_pbm,
) )
.to_physical_size(container_writing_mode); .to_physical_size(container_writing_mode);
let fragments = replaced let fragments = replaced.make_fragments(style, content_size);
.contents
.make_fragments(&replaced.style, content_size);
let content_rect = PhysicalRect::new(PhysicalPoint::zero(), content_size); let content_rect = PhysicalRect::new(PhysicalPoint::zero(), content_size);
(fragments, content_rect, None) (fragments, content_rect, None)
}, },
IndependentFormattingContext::NonReplaced(non_replaced) => { IndependentFormattingContextContents::NonReplaced(non_replaced) => {
let writing_mode = non_replaced.style.writing_mode; let writing_mode = self.style().writing_mode;
let available_inline_size = let available_inline_size =
(containing_block.inline_size - pbm_sums.inline_sum()).max(Au::zero()); (containing_block.inline_size - pbm_sums.inline_sum()).max(Au::zero());
let available_block_size = containing_block let available_block_size = containing_block
@ -2110,7 +2117,7 @@ impl IndependentFormattingContext {
let containing_block_for_children = ContainingBlock { let containing_block_for_children = ContainingBlock {
inline_size, inline_size,
block_size: tentative_block_size.to_auto_or(), block_size: tentative_block_size.to_auto_or(),
style: &non_replaced.style, style: self.style(),
}; };
assert_eq!( assert_eq!(
container_writing_mode.is_horizontal(), container_writing_mode.is_horizontal(),

View file

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

View file

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

View file

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

View file

@ -20,7 +20,9 @@ use crate::cell::ArcRefCell;
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::dom::NodeExt; use crate::dom::NodeExt;
use crate::dom_traversal::{Contents, NodeAndStyleInfo}; use crate::dom_traversal::{Contents, NodeAndStyleInfo};
use crate::formatting_contexts::IndependentFormattingContext; use crate::formatting_contexts::{
IndependentFormattingContext, IndependentFormattingContextContents,
};
use crate::fragment_tree::{ use crate::fragment_tree::{
BoxFragment, CollapsedBlockMargins, Fragment, FragmentFlags, HoistedSharedFragment, BoxFragment, CollapsedBlockMargins, Fragment, FragmentFlags, HoistedSharedFragment,
}; };
@ -521,19 +523,17 @@ impl HoistedAbsolutelyPositionedBox {
flip_anchor: false, 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-width
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-height // https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
let inset_sums = LogicalVec2 { let inset_sums = LogicalVec2 {
inline: inline_axis_solver.inset_sum(), inline: inline_axis_solver.inset_sum(),
block: block_axis_solver.inset_sum(), block: block_axis_solver.inset_sum(),
}; };
let used_size = replaced let used_size = replaced.used_size_as_if_inline_element_from_content_box_sizes(
.contents
.used_size_as_if_inline_element_from_content_box_sizes(
containing_block, containing_block,
&style, &style,
replaced.preferred_aspect_ratio(&pbm.padding_border_sums), context.preferred_aspect_ratio(&pbm.padding_border_sums),
computed_size, computed_size,
computed_min_size, computed_min_size,
computed_max_size, computed_max_size,
@ -561,20 +561,20 @@ impl HoistedAbsolutelyPositionedBox {
let mut new_fragment = { let mut new_fragment = {
let content_size: LogicalVec2<Au>; let content_size: LogicalVec2<Au>;
let fragments; let fragments;
match context { match &context.contents {
IndependentFormattingContext::Replaced(replaced) => { IndependentFormattingContextContents::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
content_size = LogicalVec2 { content_size = LogicalVec2 {
inline: inline_axis.size.to_definite().unwrap(), inline: inline_axis.size.to_definite().unwrap(),
block: block_axis.size.to_definite().unwrap(), block: block_axis.size.to_definite().unwrap(),
}; };
fragments = replaced.contents.make_fragments( fragments = replaced.make_fragments(
&style, &style,
content_size.to_physical_size(containing_block_writing_mode), 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-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.to_definite().unwrap(); 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}; use crate::{ConstraintSpace, ContainingBlock, SizeConstraint};
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub(crate) struct ReplacedContent { pub(crate) struct ReplacedContents {
pub kind: ReplacedContentKind, pub kind: ReplacedContentKind,
natural_size: NaturalSizes, natural_size: NaturalSizes,
base_fragment_info: BaseFragmentInfo, base_fragment_info: BaseFragmentInfo,
@ -140,7 +140,7 @@ pub(crate) enum ReplacedContentKind {
Video(Option<VideoInfo>), Video(Option<VideoInfo>),
} }
impl ReplacedContent { impl ReplacedContents {
pub fn for_element<'dom>(element: impl NodeExt<'dom>, context: &LayoutContext) -> Option<Self> { 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(ref data_attribute_string) = element.as_typeless_object_with_data_attribute() {
if let Some(url) = try_to_parse_image_data_url(data_attribute_string) { 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::dom_traversal::{Contents, NodeAndStyleInfo, NonReplacedContents, TraversalHandler};
use crate::flow::{BlockContainerBuilder, BlockFormattingContext}; use crate::flow::{BlockContainerBuilder, BlockFormattingContext};
use crate::formatting_contexts::{ use crate::formatting_contexts::{
IndependentFormattingContext, NonReplacedFormattingContext, IndependentFormattingContext, IndependentFormattingContextContents,
NonReplacedFormattingContextContents, IndependentNonReplacedContents,
}; };
use crate::fragment_tree::BaseFragmentInfo; use crate::fragment_tree::BaseFragmentInfo;
use crate::layout_box_base::LayoutBoxBase;
use crate::style_ext::{DisplayGeneratingBox, DisplayLayoutInternal}; use crate::style_ext::{DisplayGeneratingBox, DisplayLayoutInternal};
/// A reference to a slot and its coordinates in the table /// A reference to a slot and its coordinates in the table
@ -134,12 +135,12 @@ impl Table {
let mut table = table_builder.finish(); let mut table = table_builder.finish();
table.anonymous = true; table.anonymous = true;
IndependentFormattingContext::NonReplaced(NonReplacedFormattingContext { IndependentFormattingContext {
base_fragment_info: (&anonymous_info).into(), base: LayoutBoxBase::new((&anonymous_info).into(), grid_and_wrapper_style),
style: grid_and_wrapper_style, contents: IndependentFormattingContextContents::NonReplaced(
content_sizes_result: Default::default(), IndependentNonReplacedContents::Table(table),
contents: NonReplacedFormattingContextContents::Table(table), ),
}) }
} }
/// Push a new slot into the last row of this table. /// Push a new slot into the last row of this table.
@ -853,15 +854,13 @@ where
DisplayLayoutInternal::TableCaption => { DisplayLayoutInternal::TableCaption => {
let contents = match contents.try_into() { let contents = match contents.try_into() {
Ok(non_replaced_contents) => { Ok(non_replaced_contents) => {
NonReplacedFormattingContextContents::Flow( IndependentNonReplacedContents::Flow(BlockFormattingContext::construct(
BlockFormattingContext::construct(
self.context, self.context,
info, info,
non_replaced_contents, non_replaced_contents,
self.current_text_decoration_line, self.current_text_decoration_line,
false, /* is_list_item */ false, /* is_list_item */
), ))
)
}, },
Err(_replaced) => { Err(_replaced) => {
unreachable!("Replaced should not have a LayoutInternal display type."); unreachable!("Replaced should not have a LayoutInternal display type.");
@ -869,11 +868,9 @@ where
}; };
let caption = TableCaption { let caption = TableCaption {
context: ArcRefCell::new(NonReplacedFormattingContext { context: ArcRefCell::new(IndependentFormattingContext {
style: info.style.clone(), base: LayoutBoxBase::new(info.into(), info.style.clone()),
base_fragment_info: info.into(), contents: IndependentFormattingContextContents::NonReplaced(contents),
content_sizes_result: Default::default(),
contents,
}), }),
}; };

View file

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

View file

@ -82,7 +82,7 @@ use style_traits::dom::OpaqueNode;
use super::flow::BlockFormattingContext; use super::flow::BlockFormattingContext;
use crate::cell::ArcRefCell; use crate::cell::ArcRefCell;
use crate::flow::BlockContainer; use crate::flow::BlockContainer;
use crate::formatting_contexts::NonReplacedFormattingContext; use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragment_tree::BaseFragmentInfo; use crate::fragment_tree::BaseFragmentInfo;
pub type TableSize = Size2D<usize, UnknownUnit>; pub type TableSize = Size2D<usize, UnknownUnit>;
@ -320,5 +320,5 @@ impl TableTrackGroup {
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
pub struct TableCaption { pub struct TableCaption {
/// The contents of this cell, with its own layout. /// 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 super::{TaffyContainer, TaffyItemBox, TaffyItemBoxInner, TaffyStyloStyle};
use crate::cell::ArcRefCell; use crate::cell::ArcRefCell;
use crate::context::LayoutContext; 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::fragment_tree::{BoxFragment, CollapsedBlockMargins, Fragment};
use crate::geom::{ use crate::geom::{
LogicalSides, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalSize, Size, LogicalSides, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalSize, Size,
@ -43,13 +46,12 @@ fn resolve_content_size(constraint: AvailableSpace, content_sizes: ContentSizes)
#[inline(always)] #[inline(always)]
fn with_independant_formatting_context<T>( fn with_independant_formatting_context<T>(
item: &mut TaffyItemBoxInner, item: &mut TaffyItemBoxInner,
cb: impl FnOnce(&mut IndependentFormattingContext) -> T, cb: impl FnOnce(&IndependentFormattingContext) -> T,
) -> T { ) -> T {
match item { match item {
TaffyItemBoxInner::InFlowBox(ref mut context) => cb(context), TaffyItemBoxInner::InFlowBox(ref mut context) => cb(context),
TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(ref abspos_box) => { TaffyItemBoxInner::OutOfFlowAbsolutelyPositionedBox(ref abspos_box) => {
let mut abspos_box = AtomicRefCell::borrow_mut(abspos_box); cb(&AtomicRefCell::borrow(abspos_box).context)
cb(&mut abspos_box.context)
}, },
} }
} }
@ -132,13 +134,14 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> {
with_independant_formatting_context( with_independant_formatting_context(
&mut child.taffy_level_box, &mut child.taffy_level_box,
|independent_context| -> taffy::LayoutOutput { |independent_context| -> taffy::LayoutOutput {
match independent_context { let style = independent_context.style();
IndependentFormattingContext::Replaced(replaced) => { match &independent_context.contents {
IndependentFormattingContextContents::Replaced(replaced) => {
// TODO: re-evaluate sizing constraint conversions in light of recent layout_2020 changes // TODO: re-evaluate sizing constraint conversions in light of recent layout_2020 changes
let containing_block = &self.content_box_size_override; let containing_block = &self.content_box_size_override;
// Adjust known_dimensions from border box to content box // 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 pb_sum = pbm.padding_border_sums.map(|v| v.to_f32_px());
let content_box_known_dimensions = taffy::Size { let content_box_known_dimensions = taffy::Size {
width: inputs width: inputs
@ -152,11 +155,11 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> {
}; };
let content_box_size = replaced let content_box_size = replaced
.contents
.used_size_as_if_inline_element_from_content_box_sizes( .used_size_as_if_inline_element_from_content_box_sizes(
containing_block, containing_block,
&replaced.style, style,
replaced.preferred_aspect_ratio(&pbm.padding_border_sums), independent_context
.preferred_aspect_ratio(&pbm.padding_border_sums),
LogicalVec2 { LogicalVec2 {
inline: option_f32_to_size(content_box_known_dimensions.width), inline: option_f32_to_size(content_box_known_dimensions.width),
block: option_f32_to_size(content_box_known_dimensions.height), 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 // Create fragments if the RunMode if PerformLayout
// If the RunMode is ComputeSize then only the returned size will be used // If the RunMode is ComputeSize then only the returned size will be used
if inputs.run_mode == RunMode::PerformLayout { if inputs.run_mode == RunMode::PerformLayout {
child.child_fragments = replaced child.child_fragments =
.contents replaced.make_fragments(style, content_box_size);
.make_fragments(&replaced.style, content_box_size);
} }
let computed_size = taffy::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 // TODO: re-evaluate sizing constraint conversions in light of recent layout_2020 changes
let containing_block = &self.content_box_size_override; let containing_block = &self.content_box_size_override;
// Adjust known_dimensions from border box to content box // 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 margin_sum = pbm.margin.auto_is(Au::zero).sum();
let content_box_inset = let content_box_inset =
(pbm.padding_border_sums + margin_sum).map(|v| v.to_f32_px()); (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 { let content_box_size_override = ContainingBlock {
inline_size: Au::from_f32_px(inline_size), inline_size: Au::from_f32_px(inline_size),
block_size: maybe_block_size, block_size: maybe_block_size,
style: &non_replaced.style, style,
}; };
let layout = { let layout = {