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 <obrufau@igalia.com>
This commit is contained in:
Oriol Brufau 2024-11-11 17:26:20 +01:00 committed by GitHub
parent 5423e622ed
commit 6a62d52cbb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 75 additions and 78 deletions

View file

@ -5,6 +5,8 @@
//! Flow layout, also known as block-and-inline layout. //! Flow layout, also known as block-and-inline layout.
use std::cell::LazyCell;
use app_units::Au; use app_units::Au;
use inline::InlineFormattingContext; use inline::InlineFormattingContext;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
@ -2053,21 +2055,19 @@ impl IndependentFormattingContext {
let tentative_block_size = let tentative_block_size =
SizeConstraint::new(preferred_block_size, min_block_size, max_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); let constraint_space = ConstraintSpace::new(tentative_block_size, writing_mode);
non_replaced non_replaced
.inline_content_sizes(layout_context, &constraint_space) .inline_content_sizes(layout_context, &constraint_space)
.sizes .sizes
}; });
// https://drafts.csswg.org/css2/visudet.html#float-width // https://drafts.csswg.org/css2/visudet.html#float-width
// https://drafts.csswg.org/css2/visudet.html#inlineblock-width // https://drafts.csswg.org/css2/visudet.html#inlineblock-width
let tentative_inline_size = let tentative_inline_size = content_box_sizes_and_pbm
content_box_sizes_and_pbm.content_box_size.inline.resolve( .content_box_size
Size::FitContent, .inline
available_inline_size, .resolve(Size::FitContent, available_inline_size, &content_size);
&mut get_content_size,
);
// https://drafts.csswg.org/css2/visudet.html#min-max-widths // https://drafts.csswg.org/css2/visudet.html#min-max-widths
// In this case “applying the rules above again” with a non-auto inline-size // 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 let min_inline_size = content_box_sizes_and_pbm
.content_min_box_size .content_min_box_size
.inline .inline
.resolve_non_initial(available_inline_size, &mut get_content_size) .resolve_non_initial(available_inline_size, &content_size)
.unwrap_or_default(); .unwrap_or_default();
let max_inline_size = content_box_sizes_and_pbm let max_inline_size = content_box_sizes_and_pbm
.content_max_box_size .content_max_box_size
.inline .inline
.resolve_non_initial(available_inline_size, &mut get_content_size); .resolve_non_initial(available_inline_size, &content_size);
let inline_size = let inline_size =
tentative_inline_size.clamp_between_extremums(min_inline_size, max_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_for_children,
containing_block, containing_block,
); );
let (inline_size, block_size) = match independent_layout let (inline_size, block_size) =
.content_inline_size_for_table match independent_layout.content_inline_size_for_table {
{ Some(inline) => (inline, independent_layout.content_block_size),
Some(inline) => (inline, independent_layout.content_block_size), None => {
None => { // https://drafts.csswg.org/css2/visudet.html#block-root-margin
// https://drafts.csswg.org/css2/visudet.html#block-root-margin let stretch_size = available_block_size
let stretch_size = .unwrap_or(independent_layout.content_block_size);
available_block_size.unwrap_or(independent_layout.content_block_size); let content_size =
let mut get_content_size = || independent_layout.content_block_size.into(); LazyCell::new(|| independent_layout.content_block_size.into());
let min_block_size = content_box_sizes_and_pbm let min_block_size = content_box_sizes_and_pbm
.content_min_box_size .content_min_box_size
.block .block
.resolve_non_initial(stretch_size, &mut get_content_size) .resolve_non_initial(stretch_size, &content_size)
.unwrap_or_default(); .unwrap_or_default();
let max_block_size = content_box_sizes_and_pbm let max_block_size = content_box_sizes_and_pbm
.content_max_box_size .content_max_box_size
.block .block
.resolve_non_initial(stretch_size, &mut get_content_size); .resolve_non_initial(stretch_size, &content_size);
let block_size = tentative_block_size let block_size = tentative_block_size
.to_definite() .to_definite()
.unwrap_or(independent_layout.content_block_size) .unwrap_or(independent_layout.content_block_size)
.clamp_between_extremums(min_block_size, max_block_size); .clamp_between_extremums(min_block_size, max_block_size);
(inline_size, block_size) (inline_size, block_size)
}, },
}; };
let content_size = LogicalVec2 { let content_size = LogicalVec2 {
block: block_size, block: block_size,

View file

@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::cell::LazyCell;
use std::convert::From; use std::convert::From;
use std::fmt; use std::fmt;
use std::ops::{Add, AddAssign, Neg, Sub, SubAssign}; use std::ops::{Add, AddAssign, Neg, Sub, SubAssign};
@ -798,17 +799,17 @@ impl LogicalVec2<Size<LengthPercentage>> {
impl Size<Au> { impl Size<Au> {
/// Resolves any size into a numerical value. /// Resolves any size into a numerical value.
#[inline] #[inline]
pub(crate) fn resolve( pub(crate) fn resolve<F: FnOnce() -> ContentSizes>(
&self, &self,
initial_behavior: Self, initial_behavior: Self,
stretch_size: Au, stretch_size: Au,
get_content_size: &mut impl FnMut() -> ContentSizes, content_size: &LazyCell<ContentSizes, F>,
) -> Au { ) -> Au {
if self.is_initial() { if self.is_initial() {
assert!(!initial_behavior.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 { } else {
self.resolve_non_initial(stretch_size, get_content_size) self.resolve_non_initial(stretch_size, content_size)
} }
.unwrap() .unwrap()
} }
@ -816,16 +817,16 @@ impl Size<Au> {
/// Resolves a non-initial size into a numerical value. /// Resolves a non-initial size into a numerical value.
/// Returns `None` if the size is the initial one. /// Returns `None` if the size is the initial one.
#[inline] #[inline]
pub(crate) fn resolve_non_initial( pub(crate) fn resolve_non_initial<F: FnOnce() -> ContentSizes>(
&self, &self,
stretch_size: Au, stretch_size: Au,
get_content_size: &mut impl FnMut() -> ContentSizes, content_size: &LazyCell<ContentSizes, F>,
) -> Option<Au> { ) -> Option<Au> {
match self { match self {
Self::Initial => None, Self::Initial => None,
Self::MinContent => Some(get_content_size().min_content), Self::MinContent => Some(content_size.min_content),
Self::MaxContent => Some(get_content_size().max_content), Self::MaxContent => Some(content_size.max_content),
Self::FitContent => Some(get_content_size().shrink_to_fit(stretch_size)), Self::FitContent => Some(content_size.shrink_to_fit(stretch_size)),
Self::Stretch => Some(stretch_size), Self::Stretch => Some(stretch_size),
Self::Numeric(numeric) => Some(*numeric), Self::Numeric(numeric) => Some(*numeric),
} }

View file

@ -773,28 +773,25 @@ impl<'a> AbsoluteAxisSolver<'a> {
/// ///
/// In the replaced case, `size` is never `Auto`. /// In the replaced case, `size` is never `Auto`.
fn solve(&self, get_content_size: Option<impl FnOnce() -> ContentSizes>) -> AxisResult { fn solve(&self, get_content_size: Option<impl FnOnce() -> 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.
// 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.
// A LazyCell will only invoke it once if needed, and then reuse the result. let content_size = get_content_size.map(LazyCell::new);
let content_size = LazyCell::new(get_content_size); let solve_size = |initial_behavior, stretch_size: Au| -> SizeConstraint {
move || *content_size
});
let mut solve_size = |initial_behavior, stretch_size: Au| -> SizeConstraint {
let initial_is_stretch = initial_behavior == Size::Stretch; let initial_is_stretch = initial_behavior == Size::Stretch;
let stretch_size = stretch_size.max(Au::zero()); 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( let preferred_size = Some(self.computed_size.resolve(
initial_behavior, initial_behavior,
stretch_size, stretch_size,
&mut get_content_size, content_size,
)); ));
let min_size = self let min_size = self
.computed_min_size .computed_min_size
.resolve_non_initial(stretch_size, &mut get_content_size) .resolve_non_initial(stretch_size, content_size)
.unwrap_or_default(); .unwrap_or_default();
let max_size = self let max_size = self
.computed_max_size .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) SizeConstraint::new(preferred_size, min_size, max_size)
} else { } else {
let preferred_size = self let preferred_size = self
@ -811,7 +808,7 @@ impl<'a> AbsoluteAxisSolver<'a> {
SizeConstraint::new(preferred_size, min_size, max_size) 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_start = self.computed_margin_start.auto_is(Au::zero);
let margin_end = self.computed_margin_end.auto_is(Au::zero); let margin_end = self.computed_margin_end.auto_is(Au::zero);
let stretch_size = self.containing_size - let stretch_size = self.containing_size -

View file

@ -29,7 +29,7 @@ use crate::context::LayoutContext;
use crate::dom::NodeExt; use crate::dom::NodeExt;
use crate::fragment_tree::{BaseFragmentInfo, Fragment, IFrameFragment, ImageFragment}; use crate::fragment_tree::{BaseFragmentInfo, Fragment, IFrameFragment, ImageFragment};
use crate::geom::{LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize, Size}; 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::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM};
use crate::{ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, SizeConstraint}; use crate::{ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, SizeConstraint};
@ -561,21 +561,21 @@ impl ReplacedContent {
&get_block_size, &get_block_size,
&get_inline_fallback_size, &get_inline_fallback_size,
) )
.into()
}); });
let block_content_size = LazyCell::new(|| { let block_content_size = LazyCell::new(|| -> ContentSizes {
let get_inline_size = || { let get_inline_size = || {
let mut get_inline_content_size = || (*inline_content_size).into();
SizeConstraint::new( SizeConstraint::new(
box_size box_size
.inline .inline
.maybe_resolve_extrinsic(Some(inline_stretch_size)), .maybe_resolve_extrinsic(Some(inline_stretch_size)),
min_box_size min_box_size
.inline .inline
.resolve_non_initial(inline_stretch_size, &mut get_inline_content_size) .resolve_non_initial(inline_stretch_size, &inline_content_size)
.unwrap_or_default(), .unwrap_or_default(),
max_box_size max_box_size
.inline .inline
.resolve_non_initial(inline_stretch_size, &mut get_inline_content_size), .resolve_non_initial(inline_stretch_size, &inline_content_size),
) )
}; };
self.content_size( self.content_size(
@ -584,36 +584,35 @@ impl ReplacedContent {
&get_inline_size, &get_inline_size,
&get_block_fallback_size, &get_block_fallback_size,
) )
.into()
}); });
let mut get_inline_content_size = || (*inline_content_size).into(); let block_stretch_size =
let mut get_block_content_size = || (*block_content_size).into(); block_stretch_size.unwrap_or_else(|| block_content_size.max_content);
let block_stretch_size = block_stretch_size.unwrap_or_else(|| *block_content_size);
// <https://drafts.csswg.org/css-sizing-3/#sizing-properties> // <https://drafts.csswg.org/css-sizing-3/#sizing-properties>
let preferred_inline = box_size.inline.resolve( let preferred_inline =
Size::FitContent, box_size
inline_stretch_size, .inline
&mut get_inline_content_size, .resolve(Size::FitContent, inline_stretch_size, &inline_content_size);
); let preferred_block =
let preferred_block = box_size.block.resolve( box_size
Size::FitContent, .block
block_stretch_size, .resolve(Size::FitContent, block_stretch_size, &block_content_size);
&mut get_block_content_size,
);
let min_inline = min_box_size let min_inline = min_box_size
.inline .inline
.resolve_non_initial(inline_stretch_size, &mut get_inline_content_size) .resolve_non_initial(inline_stretch_size, &inline_content_size)
.unwrap_or_default(); .unwrap_or_default();
let min_block = min_box_size let min_block = min_box_size
.block .block
.resolve_non_initial(block_stretch_size, &mut get_block_content_size) .resolve_non_initial(block_stretch_size, &block_content_size)
.unwrap_or_default(); .unwrap_or_default();
let max_inline = max_box_size let max_inline = max_box_size
.inline .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 let max_block = max_box_size
.block .block
.resolve_non_initial(block_stretch_size, &mut get_block_content_size); .resolve_non_initial(block_stretch_size, &block_content_size);
LogicalVec2 { LogicalVec2 {
inline: preferred_inline.clamp_between_extremums(min_inline, max_inline), inline: preferred_inline.clamp_between_extremums(min_inline, max_inline),
block: preferred_block.clamp_between_extremums(min_block, max_block), block: preferred_block.clamp_between_extremums(min_block, max_block),