diff options
author | Oriol Brufau <obrufau@igalia.com> | 2025-03-24 13:33:44 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-03-24 12:33:44 +0000 |
commit | c09eed759b9533850c51ad0037fe68fab85ba6c5 (patch) | |
tree | 660dc2a9dce65c2f0d6ec7fe718d2af4be8c96c9 | |
parent | efd6e8639369308715e35532b5f29e3bc399f1ce (diff) | |
download | servo-c09eed759b9533850c51ad0037fe68fab85ba6c5.tar.gz servo-c09eed759b9533850c51ad0037fe68fab85ba6c5.zip |
layout: Cache `IndependentNonReplacedContents::layout()` (#36082)
This replaces `IndependentLayout` with `CacheableLayoutResult` and
stores it in `LayoutBoxBase` so it can be reused when we need to lay out
a box multiple times.
This is a generalization of the caching that we had for flexbox, which
is now removed in favor of the new one.
With this, the number of runs per second in the Chromium perf test
`flexbox-deeply-nested-column-flow.html` are multiplied by 3.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
-rw-r--r-- | components/layout_2020/flexbox/layout.rs | 88 | ||||
-rw-r--r-- | components/layout_2020/flexbox/mod.rs | 25 | ||||
-rw-r--r-- | components/layout_2020/flow/inline/mod.rs | 18 | ||||
-rw-r--r-- | components/layout_2020/flow/mod.rs | 49 | ||||
-rw-r--r-- | components/layout_2020/flow/root.rs | 1 | ||||
-rw-r--r-- | components/layout_2020/formatting_contexts.rs | 101 | ||||
-rw-r--r-- | components/layout_2020/fragment_tree/fragment.rs | 1 | ||||
-rw-r--r-- | components/layout_2020/layout_box_base.rs | 54 | ||||
-rw-r--r-- | components/layout_2020/lib.rs | 2 | ||||
-rw-r--r-- | components/layout_2020/positioned.rs | 5 | ||||
-rw-r--r-- | components/layout_2020/table/layout.rs | 23 | ||||
-rw-r--r-- | components/layout_2020/taffy/layout.rs | 9 |
12 files changed, 216 insertions, 160 deletions
diff --git a/components/layout_2020/flexbox/layout.rs b/components/layout_2020/flexbox/layout.rs index 77076898f57..880847617f6 100644 --- a/components/layout_2020/flexbox/layout.rs +++ b/components/layout_2020/flexbox/layout.rs @@ -25,16 +25,13 @@ use style::values::generics::length::LengthPercentageOrNormal; use style::values::specified::align::AlignFlags; use super::geom::{FlexAxis, FlexRelativeRect, FlexRelativeSides, FlexRelativeVec2}; -use super::{ - CachedBlockSizeContribution, FlexContainer, FlexContainerConfig, FlexItemBox, FlexLevelBox, -}; +use super::{FlexContainer, FlexContainerConfig, FlexItemBox, FlexLevelBox}; use crate::cell::ArcRefCell; use crate::context::LayoutContext; -use crate::formatting_contexts::{ - Baselines, IndependentFormattingContextContents, IndependentLayout, -}; +use crate::formatting_contexts::{Baselines, IndependentFormattingContextContents}; use crate::fragment_tree::{BoxFragment, CollapsedBlockMargins, Fragment, FragmentFlags}; use crate::geom::{AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, Size, Sizes}; +use crate::layout_box_base::CacheableLayoutResult; use crate::positioned::{ AbsolutelyPositionedBox, PositioningContext, PositioningContextLength, relative_adjustement, }; @@ -650,8 +647,10 @@ impl FlexContainer { layout_context: &LayoutContext, positioning_context: &mut PositioningContext, containing_block: &ContainingBlock, - ) -> IndependentLayout { - let depends_on_block_constraints = self.config.flex_direction == FlexDirection::Column; + depends_on_block_constraints: bool, + ) -> CacheableLayoutResult { + let depends_on_block_constraints = + depends_on_block_constraints || self.config.flex_direction == FlexDirection::Column; let mut flex_context = FlexContext { config: self.config.clone(), @@ -985,13 +984,14 @@ impl FlexContainer { .or(all_baselines.last), }; - IndependentLayout { + CacheableLayoutResult { fragments, content_block_size, content_inline_size_for_table: None, baselines, depends_on_block_constraints, specific_layout_info: None, + collapsible_margins_in_children: CollapsedBlockMargins::zero(), } } @@ -1950,29 +1950,23 @@ impl FlexItem<'_> { } } - let cache = self.box_.block_content_size_cache.borrow_mut().take(); - let layout = if let Some(cache) = cache.filter(|cache| { - cache.compatible_with_item_as_containing_block(&item_as_containing_block) - }) { - positioning_context = cache.positioning_context; - cache.layout - } else { - non_replaced.layout( - flex_context.layout_context, - &mut positioning_context, - &item_as_containing_block, - containing_block, - ) - }; - let IndependentLayout { + let layout = non_replaced.layout_with_caching( + flex_context.layout_context, + &mut positioning_context, + &item_as_containing_block, + containing_block, + &independent_formatting_context.base, + flex_axis == FlexAxis::Column || + self.stretches_to_line() || + self.depends_on_block_constraints, + ); + let CacheableLayoutResult { fragments, content_block_size, baselines: content_box_baselines, depends_on_block_constraints, .. } = layout; - let depends_on_block_constraints = depends_on_block_constraints || - (flex_axis == FlexAxis::Row && self.stretches_to_line()); let has_child_which_depends_on_block_constraints = fragments.iter().any(|fragment| { fragment.base().is_some_and(|base| @@ -2693,37 +2687,17 @@ impl FlexItemBox { }, style, }; - let content_block_size = || { - if let Some(cache) = &*self.block_content_size_cache.borrow() { - if inline_size == cache.containing_block_inline_size { - return cache.layout.content_block_size; - } else { - #[cfg(feature = "tracing")] - tracing::warn!( - name: "NonReplaced cache miss", - cached = ?cache.containing_block_inline_size, - required = ?inline_size, - ); - } - } else { - #[cfg(feature = "tracing")] - tracing::warn!(name: "NonReplaced no cache", required = ?inline_size); - } - - let layout = non_replaced.layout( - flex_context.layout_context, - &mut positioning_context, - &item_as_containing_block, - flex_context.containing_block, - ); - let content_block_size = layout.content_block_size; - *self.block_content_size_cache.borrow_mut() = - Some(CachedBlockSizeContribution { - containing_block_inline_size: item_as_containing_block.size.inline, - layout, - positioning_context, - }); - content_block_size + let mut content_block_size = || { + non_replaced + .layout_with_caching( + flex_context.layout_context, + &mut positioning_context, + &item_as_containing_block, + flex_context.containing_block, + &self.independent_formatting_context.base, + false, /* depends_on_block_constraints */ + ) + .content_block_size }; match intrinsic_sizing_mode { IntrinsicSizingMode::Contribution => { diff --git a/components/layout_2020/flexbox/mod.rs b/components/layout_2020/flexbox/mod.rs index fbe2786d078..46d7a2387a8 100644 --- a/components/layout_2020/flexbox/mod.rs +++ b/components/layout_2020/flexbox/mod.rs @@ -2,7 +2,6 @@ * 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 app_units::Au; use geom::{FlexAxis, MainStartCrossStart}; use servo_arc::Arc as ServoArc; use style::logical_geometry::WritingMode; @@ -13,15 +12,15 @@ use style::properties::longhands::flex_wrap::computed_value::T as FlexWrap; use style::values::computed::{AlignContent, JustifyContent}; use style::values::specified::align::AlignFlags; +use crate::PropagatedBoxTreeData; use crate::cell::ArcRefCell; use crate::construct_modern::{ModernContainerBuilder, ModernItemKind}; use crate::context::LayoutContext; use crate::dom::{LayoutBox, NodeExt}; use crate::dom_traversal::{NodeAndStyleInfo, NonReplacedContents}; -use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout}; +use crate::formatting_contexts::IndependentFormattingContext; use crate::fragment_tree::BaseFragmentInfo; -use crate::positioned::{AbsolutelyPositionedBox, PositioningContext}; -use crate::{ContainingBlock, PropagatedBoxTreeData}; +use crate::positioned::AbsolutelyPositionedBox; mod geom; mod layout; @@ -146,7 +145,6 @@ pub(crate) enum FlexLevelBox { pub(crate) struct FlexItemBox { independent_formatting_context: IndependentFormattingContext, - block_content_size_cache: ArcRefCell<Option<CachedBlockSizeContribution>>, } impl std::fmt::Debug for FlexItemBox { @@ -159,7 +157,6 @@ impl FlexItemBox { fn new(independent_formatting_context: IndependentFormattingContext) -> Self { Self { independent_formatting_context, - block_content_size_cache: Default::default(), } } @@ -171,19 +168,3 @@ impl FlexItemBox { self.independent_formatting_context.base_fragment_info() } } - -struct CachedBlockSizeContribution { - containing_block_inline_size: Au, - layout: IndependentLayout, - positioning_context: PositioningContext, -} - -impl CachedBlockSizeContribution { - fn compatible_with_item_as_containing_block( - &self, - item_as_containing_block: &ContainingBlock, - ) -> bool { - item_as_containing_block.size.inline == self.containing_block_inline_size && - !item_as_containing_block.size.block.is_definite() - } -} diff --git a/components/layout_2020/flow/inline/mod.rs b/components/layout_2020/flow/inline/mod.rs index a43a9333040..e9007ce2e45 100644 --- a/components/layout_2020/flow/inline/mod.rs +++ b/components/layout_2020/flow/inline/mod.rs @@ -109,15 +109,17 @@ use unicode_bidi::{BidiInfo, Level}; use webrender_api::FontInstanceKey; use xi_unicode::linebreak_property; -use super::IndependentFormattingContextContents; use super::float::{Clear, PlacementAmongFloats}; +use super::{ + CacheableLayoutResult, IndependentFloatOrAtomicLayoutResult, + IndependentFormattingContextContents, +}; use crate::cell::ArcRefCell; use crate::context::LayoutContext; +use crate::flow::CollapsibleWithParentStartMargin; use crate::flow::float::{FloatBox, SequentialLayoutState}; -use crate::flow::{CollapsibleWithParentStartMargin, FlowLayout}; use crate::formatting_contexts::{ - Baselines, IndependentFormattingContext, IndependentLayoutResult, - IndependentNonReplacedContents, + Baselines, IndependentFormattingContext, IndependentNonReplacedContents, }; use crate::fragment_tree::{ BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, FragmentFlags, @@ -1585,7 +1587,7 @@ impl InlineFormattingContext { containing_block: &ContainingBlock, sequential_layout_state: Option<&mut SequentialLayoutState>, collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin, - ) -> FlowLayout { + ) -> CacheableLayoutResult { let first_line_inline_start = if self.has_first_formatted_line { containing_block .style @@ -1697,12 +1699,14 @@ impl InlineFormattingContext { content_block_size == Au::zero() && collapsible_with_parent_start_margin.0; - FlowLayout { + CacheableLayoutResult { fragments: layout.fragments, content_block_size, collapsible_margins_in_children, baselines: layout.baselines, depends_on_block_constraints: layout.depends_on_block_constraints, + content_inline_size_for_table: None, + specific_layout_info: None, } } @@ -1922,7 +1926,7 @@ impl IndependentFormattingContext { // We need to know the inline size of the atomic before deciding whether to do the line break. let mut child_positioning_context = PositioningContext::new_for_style(self.style()) .unwrap_or_else(|| PositioningContext::new_for_subtree(true)); - let IndependentLayoutResult { + let IndependentFloatOrAtomicLayoutResult { mut fragment, baselines, pbm_sums, diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 58e7310d6cd..8f38e0d4b23 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -26,7 +26,7 @@ use crate::flow::float::{ }; use crate::formatting_contexts::{ Baselines, IndependentFormattingContext, IndependentFormattingContextContents, - IndependentLayout, IndependentLayoutResult, IndependentNonReplacedContents, + IndependentNonReplacedContents, }; use crate::fragment_tree::{ BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, FragmentFlags, @@ -35,7 +35,7 @@ use crate::geom::{ AuOrAuto, LogicalRect, LogicalSides, LogicalSides1D, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides, Size, Sizes, ToLogical, ToLogicalWithContainingBlock, }; -use crate::layout_box_base::LayoutBoxBase; +use crate::layout_box_base::{CacheableLayoutResult, LayoutBoxBase}; use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength}; use crate::replaced::ReplacedContents; use crate::sizing::{self, ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult}; @@ -219,18 +219,6 @@ impl BlockLevelBox { } } -pub(crate) struct FlowLayout { - pub fragments: Vec<Fragment>, - pub content_block_size: Au, - pub collapsible_margins_in_children: CollapsedBlockMargins, - /// The offset of the baselines in this layout in the content area, if there were some. This is - /// used to propagate inflow baselines to the ancestors of `display: inline-block` elements - /// and table content. - pub baselines: Baselines, - /// Whether or not this layout depends on the block size of its containing block. - pub depends_on_block_constraints: bool, -} - #[derive(Clone, Copy)] pub(crate) struct CollapsibleWithParentStartMargin(bool); @@ -362,7 +350,8 @@ impl BlockFormattingContext { layout_context: &LayoutContext, positioning_context: &mut PositioningContext, containing_block: &ContainingBlock, - ) -> IndependentLayout { + depends_on_block_constraints: bool, + ) -> CacheableLayoutResult { let mut sequential_layout_state = if self.contains_floats || !layout_context.use_rayon { Some(SequentialLayoutState::new(containing_block.size.inline)) } else { @@ -395,15 +384,17 @@ impl BlockFormattingContext { sequential_layout_state.calculate_clearance(Clear::Both, &CollapsedMargin::zero()) }); - IndependentLayout { + CacheableLayoutResult { fragments: flow_layout.fragments, content_block_size: flow_layout.content_block_size + flow_layout.collapsible_margins_in_children.end.solve() + clearance.unwrap_or_default(), content_inline_size_for_table: None, baselines: flow_layout.baselines, - depends_on_block_constraints: flow_layout.depends_on_block_constraints, + depends_on_block_constraints: depends_on_block_constraints || + flow_layout.depends_on_block_constraints, specific_layout_info: None, + collapsible_margins_in_children: CollapsedBlockMargins::zero(), } } @@ -573,7 +564,7 @@ impl BlockContainer { sequential_layout_state: Option<&mut SequentialLayoutState>, collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin, ignore_block_margins_for_stretch: LogicalSides1D<bool>, - ) -> FlowLayout { + ) -> CacheableLayoutResult { match self { BlockContainer::BlockLevelBoxes(child_boxes) => layout_block_level_children( layout_context, @@ -627,7 +618,7 @@ fn layout_block_level_children( mut sequential_layout_state: Option<&mut SequentialLayoutState>, collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin, ignore_block_margins_for_stretch: LogicalSides1D<bool>, -) -> FlowLayout { +) -> CacheableLayoutResult { let mut placement_state = PlacementState::new(collapsible_with_parent_start_margin, containing_block); @@ -660,12 +651,14 @@ fn layout_block_level_children( }); let (content_block_size, collapsible_margins_in_children, baselines) = placement_state.finish(); - FlowLayout { + CacheableLayoutResult { fragments, content_block_size, collapsible_margins_in_children, baselines, depends_on_block_constraints, + content_inline_size_for_table: None, + specific_layout_info: None, } } @@ -1150,6 +1143,7 @@ impl IndependentNonReplacedContents { positioning_context, &containing_block_for_children, containing_block, + false, /* depends_on_block_constraints */ ); let inline_size = layout @@ -1299,7 +1293,7 @@ impl IndependentNonReplacedContents { ) }; - let compute_block_size = |layout: &IndependentLayout| { + let compute_block_size = |layout: &CacheableLayoutResult| { content_box_sizes.block.resolve( Direction::Block, Size::FitContent, @@ -1335,6 +1329,7 @@ impl IndependentNonReplacedContents { style, }, containing_block, + false, /* depends_on_block_constraints */ ); content_size = LogicalVec2 { @@ -1398,6 +1393,7 @@ impl IndependentNonReplacedContents { style, }, containing_block, + false, /* depends_on_block_constraints */ ); let inline_size = if let Some(inline_size) = layout.content_inline_size_for_table { @@ -2162,6 +2158,12 @@ fn block_size_is_zero_or_intrinsic(size: &StyleSize, containing_block: &Containi } } +pub(crate) struct IndependentFloatOrAtomicLayoutResult { + pub fragment: BoxFragment, + pub baselines: Option<Baselines>, + pub pbm_sums: LogicalSides<Au>, +} + impl IndependentFormattingContext { pub(crate) fn layout_in_flow_block_level( &self, @@ -2196,7 +2198,7 @@ impl IndependentFormattingContext { layout_context: &LayoutContext, child_positioning_context: &mut PositioningContext, containing_block: &ContainingBlock, - ) -> IndependentLayoutResult { + ) -> IndependentFloatOrAtomicLayoutResult { let style = self.style(); let container_writing_mode = containing_block.style.writing_mode; let layout_style = self.layout_style(); @@ -2280,6 +2282,7 @@ impl IndependentFormattingContext { child_positioning_context, &containing_block_for_children, containing_block, + false, /* depends_on_block_constraints */ ); let inline_size = independent_layout .content_inline_size_for_table @@ -2330,7 +2333,7 @@ impl IndependentFormattingContext { CollapsedBlockMargins::zero(), ); - IndependentLayoutResult { + IndependentFloatOrAtomicLayoutResult { fragment, baselines, pbm_sums, diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs index 5b7cf077bab..4fb33bf71d4 100644 --- a/components/layout_2020/flow/root.rs +++ b/components/layout_2020/flow/root.rs @@ -365,6 +365,7 @@ impl BoxTree { layout_context, &mut positioning_context, &(&initial_containing_block).into(), + false, /* depends_on_block_constraints */ ); let mut root_fragments = independent_layout.fragments.into_iter().collect::<Vec<_>>(); diff --git a/components/layout_2020/formatting_contexts.rs b/components/layout_2020/formatting_contexts.rs index 96b78bf6eef..573e9100cec 100644 --- a/components/layout_2020/formatting_contexts.rs +++ b/components/layout_2020/formatting_contexts.rs @@ -12,11 +12,10 @@ use crate::dom::NodeExt; use crate::dom_traversal::{Contents, NodeAndStyleInfo}; use crate::flexbox::FlexContainer; use crate::flow::BlockFormattingContext; -use crate::fragment_tree::{ - BaseFragmentInfo, BoxFragment, Fragment, FragmentFlags, SpecificLayoutInfo, +use crate::fragment_tree::{BaseFragmentInfo, FragmentFlags}; +use crate::layout_box_base::{ + CacheableLayoutResult, CacheableLayoutResultAndInputs, LayoutBoxBase, }; -use crate::geom::LogicalSides; -use crate::layout_box_base::LayoutBoxBase; use crate::positioned::PositioningContext; use crate::replaced::ReplacedContents; use crate::sizing::{self, ComputeInlineContentSizes, InlineContentSizesResult}; @@ -68,35 +67,6 @@ impl Baselines { } } -pub(crate) struct IndependentLayout { - pub fragments: Vec<Fragment>, - - /// <https://drafts.csswg.org/css2/visudet.html#root-height> - pub content_block_size: Au, - - /// If a table has collapsed columns, it can become smaller than what the parent - /// formatting context decided. This is the resulting inline content size. - /// This is None for non-table layouts and for tables without collapsed columns. - pub content_inline_size_for_table: Option<Au>, - - /// The offset of the last inflow baseline of this layout in the content area, if - /// there was one. This is used to propagate baselines to the ancestors of `display: - /// inline-block`. - pub baselines: Baselines, - - /// Whether or not this layout depends on the containing block size. - pub depends_on_block_constraints: bool, - - /// Additional information of this layout that could be used by Javascripts and devtools. - pub specific_layout_info: Option<SpecificLayoutInfo>, -} - -pub(crate) struct IndependentLayoutResult { - pub fragment: BoxFragment, - pub baselines: Option<Baselines>, - pub pbm_sums: LogicalSides<Au>, -} - impl IndependentFormattingContext { pub fn construct<'dom, Node: NodeExt<'dom>>( context: &LayoutContext, @@ -255,17 +225,20 @@ impl IndependentNonReplacedContents { positioning_context: &mut PositioningContext, containing_block_for_children: &ContainingBlock, containing_block: &ContainingBlock, - ) -> IndependentLayout { + depends_on_block_constraints: bool, + ) -> CacheableLayoutResult { match self { IndependentNonReplacedContents::Flow(bfc) => bfc.layout( layout_context, positioning_context, containing_block_for_children, + depends_on_block_constraints, ), IndependentNonReplacedContents::Flex(fc) => fc.layout( layout_context, positioning_context, containing_block_for_children, + depends_on_block_constraints, ), IndependentNonReplacedContents::Grid(fc) => fc.layout( layout_context, @@ -278,10 +251,70 @@ impl IndependentNonReplacedContents { positioning_context, containing_block_for_children, containing_block, + depends_on_block_constraints, ), } } + #[cfg_attr( + feature = "tracing", + tracing::instrument( + name = "IndependentNonReplacedContents::layout_with_caching", + skip_all, + fields(servo_profiling = true), + level = "trace", + ) + )] + pub fn layout_with_caching( + &self, + layout_context: &LayoutContext, + positioning_context: &mut PositioningContext, + containing_block_for_children: &ContainingBlock, + containing_block: &ContainingBlock, + base: &LayoutBoxBase, + depends_on_block_constraints: bool, + ) -> CacheableLayoutResult { + if let Some(cache) = base.cached_layout_result.borrow().as_ref() { + if cache.containing_block_for_children_size.inline == + containing_block_for_children.size.inline && + (cache.containing_block_for_children_size.block == + containing_block_for_children.size.block || + !(cache.result.depends_on_block_constraints || + depends_on_block_constraints)) + { + positioning_context.append(cache.positioning_context.clone()); + return cache.result.clone(); + } + #[cfg(feature = "tracing")] + tracing::debug!( + name: "NonReplaced cache miss", + cached = ?cache.containing_block_for_children_size, + required = ?containing_block_for_children.size, + ); + } + + let mut child_positioning_context = PositioningContext::new_for_subtree( + positioning_context.collects_for_nearest_positioned_ancestor(), + ); + + let result = self.layout( + layout_context, + &mut child_positioning_context, + containing_block_for_children, + containing_block, + depends_on_block_constraints, + ); + + *base.cached_layout_result.borrow_mut() = Some(CacheableLayoutResultAndInputs { + result: result.clone(), + positioning_context: child_positioning_context.clone(), + containing_block_for_children_size: containing_block_for_children.size.clone(), + }); + positioning_context.append(child_positioning_context); + + result + } + #[inline] pub(crate) fn layout_style<'a>(&'a self, base: &'a LayoutBoxBase) -> LayoutStyle<'a> { match self { diff --git a/components/layout_2020/fragment_tree/fragment.rs b/components/layout_2020/fragment_tree/fragment.rs index ba52f28bc3b..fbc95ce3d5a 100644 --- a/components/layout_2020/fragment_tree/fragment.rs +++ b/components/layout_2020/fragment_tree/fragment.rs @@ -45,6 +45,7 @@ pub(crate) enum Fragment { IFrame(ArcRefCell<IFrameFragment>), } +#[derive(Clone)] pub(crate) struct CollapsedBlockMargins { pub collapsed_through: bool, pub start: CollapsedMargin, diff --git a/components/layout_2020/layout_box_base.rs b/components/layout_2020/layout_box_base.rs index 0de9987bde7..bb2d37698f1 100644 --- a/components/layout_2020/layout_box_base.rs +++ b/components/layout_2020/layout_box_base.rs @@ -2,15 +2,20 @@ * 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 std::fmt::{Debug, Formatter}; + +use app_units::Au; use atomic_refcell::AtomicRefCell; use servo_arc::Arc; use style::properties::ComputedValues; -use crate::ConstraintSpace; use crate::context::LayoutContext; -use crate::fragment_tree::BaseFragmentInfo; +use crate::formatting_contexts::Baselines; +use crate::fragment_tree::{BaseFragmentInfo, CollapsedBlockMargins, Fragment, SpecificLayoutInfo}; use crate::geom::SizeConstraint; +use crate::positioned::PositioningContext; use crate::sizing::{ComputeInlineContentSizes, InlineContentSizesResult}; +use crate::{ConstraintSpace, ContainingBlockSize}; /// 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 @@ -18,12 +23,12 @@ use crate::sizing::{ComputeInlineContentSizes, InlineContentSizesResult}; /// passes. /// /// In the future, this will hold layout results to support incremental layout. -#[derive(Debug)] pub(crate) struct LayoutBoxBase { pub base_fragment_info: BaseFragmentInfo, pub style: Arc<ComputedValues>, pub cached_inline_content_size: AtomicRefCell<Option<(SizeConstraint, InlineContentSizesResult)>>, + pub cached_layout_result: AtomicRefCell<Option<CacheableLayoutResultAndInputs>>, } impl LayoutBoxBase { @@ -32,6 +37,7 @@ impl LayoutBoxBase { base_fragment_info, style, cached_inline_content_size: AtomicRefCell::default(), + cached_layout_result: AtomicRefCell::default(), } } @@ -58,3 +64,45 @@ impl LayoutBoxBase { result } } + +impl Debug for LayoutBoxBase { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + f.debug_struct("LayoutBoxBase").finish() + } +} + +#[derive(Clone)] +pub(crate) struct CacheableLayoutResult { + pub fragments: Vec<Fragment>, + + /// <https://drafts.csswg.org/css2/visudet.html#root-height> + pub content_block_size: Au, + + /// If this layout is for a block container, this tracks the collapsable size + /// of start and end margins and whether or not the block container collapsed through. + pub collapsible_margins_in_children: CollapsedBlockMargins, + + /// The contents of a table may force it to become wider than what we would expect + /// from 'width' and 'min-width'. This is the resulting inline content size, + /// or None for non-table layouts. + pub content_inline_size_for_table: Option<Au>, + + /// The offset of the last inflow baseline of this layout in the content area, if + /// there was one. This is used to propagate baselines to the ancestors of `display: + /// inline-block`. + pub baselines: Baselines, + + /// Whether or not this layout depends on the containing block size. + pub depends_on_block_constraints: bool, + + /// Additional information of this layout that could be used by Javascripts and devtools. + pub specific_layout_info: Option<SpecificLayoutInfo>, +} + +pub(crate) struct CacheableLayoutResultAndInputs { + pub result: CacheableLayoutResult, + + pub containing_block_for_children_size: ContainingBlockSize, + + pub positioning_context: PositioningContext, +} diff --git a/components/layout_2020/lib.rs b/components/layout_2020/lib.rs index 780d670c541..640f9ff938b 100644 --- a/components/layout_2020/lib.rs +++ b/components/layout_2020/lib.rs @@ -112,7 +112,7 @@ impl<'a> From<&'_ DefiniteContainingBlock<'a>> for IndefiniteContainingBlock { } } -#[derive(Debug)] +#[derive(Clone, Debug)] pub(crate) struct ContainingBlockSize { inline: Au, block: SizeConstraint, diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index 8b10a79b59c..238eb1e3b2a 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -41,6 +41,7 @@ pub(crate) struct AbsolutelyPositionedBox { pub context: IndependentFormattingContext, } +#[derive(Clone)] pub(crate) struct PositioningContext { for_nearest_positioned_ancestor: Option<Vec<HoistedAbsolutelyPositionedBox>>, @@ -50,6 +51,7 @@ pub(crate) struct PositioningContext { for_nearest_containing_block_for_all_descendants: Vec<HoistedAbsolutelyPositionedBox>, } +#[derive(Clone)] pub(crate) struct HoistedAbsolutelyPositionedBox { absolutely_positioned_box: ArcRefCell<AbsolutelyPositionedBox>, @@ -299,7 +301,7 @@ impl PositioningContext { .push(box_) } - fn is_empty(&self) -> bool { + pub(crate) fn is_empty(&self) -> bool { self.for_nearest_containing_block_for_all_descendants .is_empty() && self.for_nearest_positioned_ancestor @@ -627,6 +629,7 @@ impl HoistedAbsolutelyPositionedBox { &mut positioning_context, &containing_block_for_children, containing_block, + false, /* depends_on_block_constraints */ ); let inline_size = if let Some(inline_size) = diff --git a/components/layout_2020/table/layout.rs b/components/layout_2020/table/layout.rs index 29014ae171c..ed35cff6049 100644 --- a/components/layout_2020/table/layout.rs +++ b/components/layout_2020/table/layout.rs @@ -29,7 +29,7 @@ use super::{ TableLayoutStyle, TableSlot, TableSlotCell, TableSlotCoordinates, TableTrack, TableTrackGroup, }; use crate::context::LayoutContext; -use crate::formatting_contexts::{Baselines, IndependentLayout}; +use crate::formatting_contexts::Baselines; use crate::fragment_tree::{ BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, ExtraBackground, Fragment, FragmentFlags, PositioningFragment, SpecificLayoutInfo, @@ -38,6 +38,7 @@ use crate::geom::{ LogicalRect, LogicalSides, LogicalSides1D, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalVec, Size, SizeConstraint, ToLogical, ToLogicalWithContainingBlock, }; +use crate::layout_box_base::CacheableLayoutResult; use crate::positioned::{PositioningContext, PositioningContextLength, relative_adjustement}; use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult}; use crate::style_ext::{ @@ -51,7 +52,7 @@ use crate::{ /// the table. Note that this is only done for slots that are not /// covered by spans or empty. struct CellLayout { - layout: IndependentLayout, + layout: CacheableLayoutResult, padding: LogicalSides<Au>, border: LogicalSides<Au>, positioning_context: PositioningContext, @@ -1137,6 +1138,7 @@ impl<'a> TableLayout<'a> { layout_context, &mut positioning_context, &containing_block_for_children, + false, /* depends_on_block_constraints */ ); Some(CellLayout { @@ -1539,13 +1541,15 @@ impl<'a> TableLayout<'a> { positioning_context: &mut PositioningContext, containing_block_for_children: &ContainingBlock, containing_block_for_table: &ContainingBlock, - ) -> IndependentLayout { + depends_on_block_constraints: bool, + ) -> CacheableLayoutResult { let table_writing_mode = containing_block_for_children.style.writing_mode; self.compute_border_collapse(table_writing_mode); let layout_style = self.table.layout_style(Some(&self)); - let depends_on_block_constraints = layout_style - .content_box_sizes_and_padding_border_margin(&containing_block_for_table.into()) - .depends_on_block_constraints; + let depends_on_block_constraints = depends_on_block_constraints || + layout_style + .content_box_sizes_and_padding_border_margin(&containing_block_for_table.into()) + .depends_on_block_constraints; self.pbm = layout_style .padding_border_margin_with_writing_mode_and_containing_block_inline_size( @@ -1579,13 +1583,14 @@ impl<'a> TableLayout<'a> { let offset_from_wrapper = -self.pbm.padding - self.pbm.border; let mut current_block_offset = offset_from_wrapper.block_start; - let mut table_layout = IndependentLayout { + let mut table_layout = CacheableLayoutResult { fragments: Vec::new(), content_block_size: Zero::zero(), content_inline_size_for_table: None, baselines: Baselines::default(), depends_on_block_constraints, specific_layout_info: Some(SpecificLayoutInfo::TableWrapper), + collapsible_margins_in_children: CollapsedBlockMargins::zero(), }; table_layout @@ -2664,12 +2669,14 @@ impl Table { positioning_context: &mut PositioningContext, containing_block_for_children: &ContainingBlock, containing_block_for_table: &ContainingBlock, - ) -> IndependentLayout { + depends_on_block_constraints: bool, + ) -> CacheableLayoutResult { TableLayout::new(self).layout( layout_context, positioning_context, containing_block_for_children, containing_block_for_table, + depends_on_block_constraints, ) } } diff --git a/components/layout_2020/taffy/layout.rs b/components/layout_2020/taffy/layout.rs index 1e58464629f..6c1b931599c 100644 --- a/components/layout_2020/taffy/layout.rs +++ b/components/layout_2020/taffy/layout.rs @@ -18,7 +18,6 @@ use crate::cell::ArcRefCell; use crate::context::LayoutContext; use crate::formatting_contexts::{ Baselines, IndependentFormattingContext, IndependentFormattingContextContents, - IndependentLayout, }; use crate::fragment_tree::{ BoxFragment, CollapsedBlockMargins, Fragment, FragmentFlags, SpecificLayoutInfo, @@ -27,6 +26,7 @@ use crate::geom::{ LogicalSides, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalSize, Size, SizeConstraint, Sizes, }; +use crate::layout_box_base::CacheableLayoutResult; use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength}; use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult}; use crate::style_ext::{ComputedValuesExt, LayoutStyle}; @@ -264,6 +264,7 @@ impl taffy::LayoutPartialTree for TaffyContainerContext<'_> { &mut child_positioning_context, &content_box_size_override, containing_block, + false, /* depends_on_block_constraints */ ); // Store layout data on child for later access @@ -425,7 +426,7 @@ impl TaffyContainer { positioning_context: &mut PositioningContext, content_box_size_override: &ContainingBlock, containing_block: &ContainingBlock, - ) -> IndependentLayout { + ) -> CacheableLayoutResult { let mut container_ctx = TaffyContainerContext { layout_context, positioning_context, @@ -643,7 +644,7 @@ impl TaffyContainer { }) .collect(); - IndependentLayout { + CacheableLayoutResult { fragments, content_block_size: Au::from_f32_px(output.size.height) - pbm.padding_border_sums.block, content_inline_size_for_table: None, @@ -654,8 +655,8 @@ impl TaffyContainer { // "true" is a safe default as it will prevent Servo from performing optimizations based // on the assumption that the node's size does not depend on block constraints. depends_on_block_constraints: true, - specific_layout_info: container_ctx.specific_layout_info, + collapsible_margins_in_children: CollapsedBlockMargins::zero(), } } |