From 6a62d52cbb0385276de617c956a0e1d880469bc9 Mon Sep 17 00:00:00 2001 From: Oriol Brufau Date: Mon, 11 Nov 2024 17:26:20 +0100 Subject: [PATCH] Use LazyCells instead of callbacks when resolving size keywords (#34211) In most cases we already had a LazyCell anyways, since we could need the value for multiple properties. Instead of passing a callback that forces the evaluation of the LazyCell, it's simpler to just pass the LazyCell directly. Also, this way we no longer need mutable references. Signed-off-by: Oriol Brufau --- components/layout_2020/flow/mod.rs | 70 ++++++++++++++-------------- components/layout_2020/geom.rs | 19 ++++---- components/layout_2020/positioned.rs | 21 ++++----- components/layout_2020/replaced.rs | 43 +++++++++-------- 4 files changed, 75 insertions(+), 78 deletions(-) diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs index 94a8bb55931..2a444b28fed 100644 --- a/components/layout_2020/flow/mod.rs +++ b/components/layout_2020/flow/mod.rs @@ -5,6 +5,8 @@ //! Flow layout, also known as block-and-inline layout. +use std::cell::LazyCell; + use app_units::Au; use inline::InlineFormattingContext; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; @@ -2053,21 +2055,19 @@ impl IndependentFormattingContext { let tentative_block_size = SizeConstraint::new(preferred_block_size, min_block_size, max_block_size); - let mut get_content_size = || { + let content_size = LazyCell::new(|| { let constraint_space = ConstraintSpace::new(tentative_block_size, writing_mode); non_replaced .inline_content_sizes(layout_context, &constraint_space) .sizes - }; + }); // https://drafts.csswg.org/css2/visudet.html#float-width // https://drafts.csswg.org/css2/visudet.html#inlineblock-width - let tentative_inline_size = - content_box_sizes_and_pbm.content_box_size.inline.resolve( - Size::FitContent, - available_inline_size, - &mut get_content_size, - ); + let tentative_inline_size = content_box_sizes_and_pbm + .content_box_size + .inline + .resolve(Size::FitContent, available_inline_size, &content_size); // https://drafts.csswg.org/css2/visudet.html#min-max-widths // In this case “applying the rules above again” with a non-auto inline-size @@ -2075,12 +2075,12 @@ impl IndependentFormattingContext { let min_inline_size = content_box_sizes_and_pbm .content_min_box_size .inline - .resolve_non_initial(available_inline_size, &mut get_content_size) + .resolve_non_initial(available_inline_size, &content_size) .unwrap_or_default(); let max_inline_size = content_box_sizes_and_pbm .content_max_box_size .inline - .resolve_non_initial(available_inline_size, &mut get_content_size); + .resolve_non_initial(available_inline_size, &content_size); let inline_size = tentative_inline_size.clamp_between_extremums(min_inline_size, max_inline_size); @@ -2101,31 +2101,31 @@ impl IndependentFormattingContext { &containing_block_for_children, containing_block, ); - let (inline_size, block_size) = match independent_layout - .content_inline_size_for_table - { - Some(inline) => (inline, independent_layout.content_block_size), - None => { - // https://drafts.csswg.org/css2/visudet.html#block-root-margin - let stretch_size = - available_block_size.unwrap_or(independent_layout.content_block_size); - let mut get_content_size = || independent_layout.content_block_size.into(); - let min_block_size = content_box_sizes_and_pbm - .content_min_box_size - .block - .resolve_non_initial(stretch_size, &mut get_content_size) - .unwrap_or_default(); - let max_block_size = content_box_sizes_and_pbm - .content_max_box_size - .block - .resolve_non_initial(stretch_size, &mut get_content_size); - let block_size = tentative_block_size - .to_definite() - .unwrap_or(independent_layout.content_block_size) - .clamp_between_extremums(min_block_size, max_block_size); - (inline_size, block_size) - }, - }; + let (inline_size, block_size) = + match independent_layout.content_inline_size_for_table { + Some(inline) => (inline, independent_layout.content_block_size), + None => { + // https://drafts.csswg.org/css2/visudet.html#block-root-margin + let stretch_size = available_block_size + .unwrap_or(independent_layout.content_block_size); + let content_size = + LazyCell::new(|| independent_layout.content_block_size.into()); + let min_block_size = content_box_sizes_and_pbm + .content_min_box_size + .block + .resolve_non_initial(stretch_size, &content_size) + .unwrap_or_default(); + let max_block_size = content_box_sizes_and_pbm + .content_max_box_size + .block + .resolve_non_initial(stretch_size, &content_size); + let block_size = tentative_block_size + .to_definite() + .unwrap_or(independent_layout.content_block_size) + .clamp_between_extremums(min_block_size, max_block_size); + (inline_size, block_size) + }, + }; let content_size = LogicalVec2 { block: block_size, diff --git a/components/layout_2020/geom.rs b/components/layout_2020/geom.rs index ba7349ad81f..0ac98b443fc 100644 --- a/components/layout_2020/geom.rs +++ b/components/layout_2020/geom.rs @@ -2,6 +2,7 @@ * 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::cell::LazyCell; use std::convert::From; use std::fmt; use std::ops::{Add, AddAssign, Neg, Sub, SubAssign}; @@ -798,17 +799,17 @@ impl LogicalVec2> { impl Size { /// Resolves any size into a numerical value. #[inline] - pub(crate) fn resolve( + pub(crate) fn resolve ContentSizes>( &self, initial_behavior: Self, stretch_size: Au, - get_content_size: &mut impl FnMut() -> ContentSizes, + content_size: &LazyCell, ) -> Au { if self.is_initial() { assert!(!initial_behavior.is_initial()); - initial_behavior.resolve_non_initial(stretch_size, get_content_size) + initial_behavior.resolve_non_initial(stretch_size, content_size) } else { - self.resolve_non_initial(stretch_size, get_content_size) + self.resolve_non_initial(stretch_size, content_size) } .unwrap() } @@ -816,16 +817,16 @@ impl Size { /// Resolves a non-initial size into a numerical value. /// Returns `None` if the size is the initial one. #[inline] - pub(crate) fn resolve_non_initial( + pub(crate) fn resolve_non_initial ContentSizes>( &self, stretch_size: Au, - get_content_size: &mut impl FnMut() -> ContentSizes, + content_size: &LazyCell, ) -> Option { match self { Self::Initial => None, - Self::MinContent => Some(get_content_size().min_content), - Self::MaxContent => Some(get_content_size().max_content), - Self::FitContent => Some(get_content_size().shrink_to_fit(stretch_size)), + Self::MinContent => Some(content_size.min_content), + Self::MaxContent => Some(content_size.max_content), + Self::FitContent => Some(content_size.shrink_to_fit(stretch_size)), Self::Stretch => Some(stretch_size), Self::Numeric(numeric) => Some(*numeric), } diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs index 8b59b72216f..f53c4142d20 100644 --- a/components/layout_2020/positioned.rs +++ b/components/layout_2020/positioned.rs @@ -773,28 +773,25 @@ impl<'a> AbsoluteAxisSolver<'a> { /// /// In the replaced case, `size` is never `Auto`. fn solve(&self, get_content_size: Option ContentSizes>) -> AxisResult { - let mut get_content_size = get_content_size.map(|get_content_size| { - // The provided `get_content_size` is a FnOnce but we may need its result multiple times. - // A LazyCell will only invoke it once if needed, and then reuse the result. - let content_size = LazyCell::new(get_content_size); - move || *content_size - }); - let mut solve_size = |initial_behavior, stretch_size: Au| -> SizeConstraint { + // The provided `get_content_size` is a FnOnce but we may need its result multiple times. + // A LazyCell will only invoke it once if needed, and then reuse the result. + let content_size = get_content_size.map(LazyCell::new); + let solve_size = |initial_behavior, stretch_size: Au| -> SizeConstraint { let initial_is_stretch = initial_behavior == Size::Stretch; let stretch_size = stretch_size.max(Au::zero()); - if let Some(mut get_content_size) = get_content_size.as_mut() { + if let Some(ref content_size) = content_size { let preferred_size = Some(self.computed_size.resolve( initial_behavior, stretch_size, - &mut get_content_size, + content_size, )); let min_size = self .computed_min_size - .resolve_non_initial(stretch_size, &mut get_content_size) + .resolve_non_initial(stretch_size, content_size) .unwrap_or_default(); let max_size = self .computed_max_size - .resolve_non_initial(stretch_size, &mut get_content_size); + .resolve_non_initial(stretch_size, content_size); SizeConstraint::new(preferred_size, min_size, max_size) } else { let preferred_size = self @@ -811,7 +808,7 @@ impl<'a> AbsoluteAxisSolver<'a> { SizeConstraint::new(preferred_size, min_size, max_size) } }; - let mut solve_for_anchor = |anchor: Anchor| { + let solve_for_anchor = |anchor: Anchor| { let margin_start = self.computed_margin_start.auto_is(Au::zero); let margin_end = self.computed_margin_end.auto_is(Au::zero); let stretch_size = self.containing_size - diff --git a/components/layout_2020/replaced.rs b/components/layout_2020/replaced.rs index 8aa2b567212..ffbb5244ffa 100644 --- a/components/layout_2020/replaced.rs +++ b/components/layout_2020/replaced.rs @@ -29,7 +29,7 @@ use crate::context::LayoutContext; use crate::dom::NodeExt; use crate::fragment_tree::{BaseFragmentInfo, Fragment, IFrameFragment, ImageFragment}; use crate::geom::{LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize, Size}; -use crate::sizing::InlineContentSizesResult; +use crate::sizing::{ContentSizes, InlineContentSizesResult}; use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM}; use crate::{ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, SizeConstraint}; @@ -561,21 +561,21 @@ impl ReplacedContent { &get_block_size, &get_inline_fallback_size, ) + .into() }); - let block_content_size = LazyCell::new(|| { + let block_content_size = LazyCell::new(|| -> ContentSizes { let get_inline_size = || { - let mut get_inline_content_size = || (*inline_content_size).into(); SizeConstraint::new( box_size .inline .maybe_resolve_extrinsic(Some(inline_stretch_size)), min_box_size .inline - .resolve_non_initial(inline_stretch_size, &mut get_inline_content_size) + .resolve_non_initial(inline_stretch_size, &inline_content_size) .unwrap_or_default(), max_box_size .inline - .resolve_non_initial(inline_stretch_size, &mut get_inline_content_size), + .resolve_non_initial(inline_stretch_size, &inline_content_size), ) }; self.content_size( @@ -584,36 +584,35 @@ impl ReplacedContent { &get_inline_size, &get_block_fallback_size, ) + .into() }); - let mut get_inline_content_size = || (*inline_content_size).into(); - let mut get_block_content_size = || (*block_content_size).into(); - let block_stretch_size = block_stretch_size.unwrap_or_else(|| *block_content_size); + let block_stretch_size = + block_stretch_size.unwrap_or_else(|| block_content_size.max_content); // - let preferred_inline = box_size.inline.resolve( - Size::FitContent, - inline_stretch_size, - &mut get_inline_content_size, - ); - let preferred_block = box_size.block.resolve( - Size::FitContent, - block_stretch_size, - &mut get_block_content_size, - ); + let preferred_inline = + box_size + .inline + .resolve(Size::FitContent, inline_stretch_size, &inline_content_size); + let preferred_block = + box_size + .block + .resolve(Size::FitContent, block_stretch_size, &block_content_size); let min_inline = min_box_size .inline - .resolve_non_initial(inline_stretch_size, &mut get_inline_content_size) + .resolve_non_initial(inline_stretch_size, &inline_content_size) .unwrap_or_default(); let min_block = min_box_size .block - .resolve_non_initial(block_stretch_size, &mut get_block_content_size) + .resolve_non_initial(block_stretch_size, &block_content_size) .unwrap_or_default(); let max_inline = max_box_size .inline - .resolve_non_initial(inline_stretch_size, &mut get_inline_content_size); + .resolve_non_initial(inline_stretch_size, &inline_content_size); let max_block = max_box_size .block - .resolve_non_initial(block_stretch_size, &mut get_block_content_size); + .resolve_non_initial(block_stretch_size, &block_content_size); + LogicalVec2 { inline: preferred_inline.clamp_between_extremums(min_inline, max_inline), block: preferred_block.clamp_between_extremums(min_block, max_block),