mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Refactor box size computation (#34671)
in each layout logic, in order to correctly resolve sizing keywords. This patch adds a new `Sizes` struct which holds the preferred, min and max sizing values for one axis, and unifies the logic to resolve the final size into there. Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
28e330c9b6
commit
e2a0ac07ff
8 changed files with 311 additions and 343 deletions
|
@ -870,3 +870,122 @@ impl SizeConstraint {
|
|||
.map_or(AutoOr::Auto, AutoOr::LengthPercentage)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct Sizes {
|
||||
/// <https://drafts.csswg.org/css-sizing-3/#preferred-size-properties>
|
||||
pub preferred: Size<Au>,
|
||||
/// <https://drafts.csswg.org/css-sizing-3/#min-size-properties>
|
||||
pub min: Size<Au>,
|
||||
/// <https://drafts.csswg.org/css-sizing-3/#max-size-properties>
|
||||
pub max: Size<Au>,
|
||||
}
|
||||
|
||||
impl Sizes {
|
||||
#[inline]
|
||||
pub(crate) fn new(preferred: Size<Au>, min: Size<Au>, max: Size<Au>) -> Self {
|
||||
Self {
|
||||
preferred,
|
||||
min,
|
||||
max,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn depends_on_available_space(&self) -> bool {
|
||||
// TODO: this logic could be refined further, since even if some of the 3 sizes
|
||||
// depends on the available space, the resulting size might not. For example,
|
||||
// `min-width: 200px; width: 100px; max-width: stretch`.
|
||||
matches!(
|
||||
self.preferred,
|
||||
Size::Initial | Size::Stretch | Size::FitContent
|
||||
) || matches!(self.min, Size::Stretch | Size::FitContent) ||
|
||||
matches!(self.max, Size::Stretch | Size::FitContent)
|
||||
}
|
||||
|
||||
/// Resolves the three sizes into a single numerical value.
|
||||
#[inline]
|
||||
pub(crate) fn resolve(
|
||||
&self,
|
||||
automatic_size: Size<Au>,
|
||||
automatic_minimum_size: Au,
|
||||
stretch_size: Au,
|
||||
get_content_size: impl FnOnce() -> ContentSizes,
|
||||
) -> Au {
|
||||
let (preferred, min, max) = self.resolve_each(
|
||||
automatic_size,
|
||||
automatic_minimum_size,
|
||||
stretch_size,
|
||||
get_content_size,
|
||||
);
|
||||
preferred.clamp_between_extremums(min, max)
|
||||
}
|
||||
|
||||
/// Resolves each of the three sizes into a numerical value, separately.
|
||||
#[inline]
|
||||
pub(crate) fn resolve_each(
|
||||
&self,
|
||||
automatic_size: Size<Au>,
|
||||
automatic_minimum_size: Au,
|
||||
stretch_size: Au,
|
||||
get_content_size: impl FnOnce() -> ContentSizes,
|
||||
) -> (Au, Au, Option<Au>) {
|
||||
// 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);
|
||||
(
|
||||
self.preferred
|
||||
.resolve(automatic_size, stretch_size, &content_size),
|
||||
self.min
|
||||
.resolve_non_initial(stretch_size, &content_size)
|
||||
.unwrap_or(automatic_minimum_size),
|
||||
self.max.resolve_non_initial(stretch_size, &content_size),
|
||||
)
|
||||
}
|
||||
|
||||
/// Tries to extrinsically resolve the three sizes into a single [`SizeConstraint`].
|
||||
/// Values that are intrinsic or need `stretch_size` when it's `None` are handled as such:
|
||||
/// - On the preferred size, they make the returned value be an indefinite [`SizeConstraint::MinMax`].
|
||||
/// - On the min size, they are treated as `auto`, enforcing the automatic minimum size.
|
||||
/// - On the max size, they are treated as `none`, enforcing no maximum.
|
||||
#[inline]
|
||||
pub(crate) fn resolve_extrinsic(
|
||||
&self,
|
||||
automatic_size: Size<Au>,
|
||||
automatic_minimum_size: Au,
|
||||
stretch_size: Option<Au>,
|
||||
) -> SizeConstraint {
|
||||
let (preferred, min, max) =
|
||||
self.resolve_each_extrinsic(automatic_size, automatic_minimum_size, stretch_size);
|
||||
SizeConstraint::new(preferred, min, max)
|
||||
}
|
||||
|
||||
/// Tries to extrinsically resolve each of the three sizes into a numerical value, separately.
|
||||
/// This can't resolve values that are intrinsic or need `stretch_size` but it's `None`.
|
||||
/// - The 1st returned value is the resolved preferred size. If it can't be resolved then
|
||||
/// the returned value is `None`. Note that this is different than treating it as `auto`.
|
||||
/// TODO: This needs to be discussed in <https://github.com/w3c/csswg-drafts/issues/11387>.
|
||||
/// - The 2nd returned value is the resolved minimum size. If it can't be resolved then we
|
||||
/// treat it as the initial `auto`, returning the automatic minimum size.
|
||||
/// - The 3rd returned value is the resolved maximum size. If it can't be resolved then we
|
||||
/// treat it as the initial `none`, returning `None`.
|
||||
#[inline]
|
||||
pub(crate) fn resolve_each_extrinsic(
|
||||
&self,
|
||||
automatic_size: Size<Au>,
|
||||
automatic_minimum_size: Au,
|
||||
stretch_size: Option<Au>,
|
||||
) -> (Option<Au>, Au, Option<Au>) {
|
||||
(
|
||||
if self.preferred.is_initial() {
|
||||
automatic_size.maybe_resolve_extrinsic(stretch_size)
|
||||
} else {
|
||||
self.preferred.maybe_resolve_extrinsic(stretch_size)
|
||||
},
|
||||
self.min
|
||||
.maybe_resolve_extrinsic(stretch_size)
|
||||
.unwrap_or(automatic_minimum_size),
|
||||
self.max.maybe_resolve_extrinsic(stretch_size),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue