mirror of
https://github.com/servo/servo.git
synced 2025-08-16 19:05:33 +01:00
layout: Move sizing logic from geom.rs to sizing.rs (#38568)
Moves `Size`, `SizeConstraint`, `Sizes` and `LazySizeData`. Testing: Not needed, no change in behavior. Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
d5d3ad6949
commit
7ff8724eaf
12 changed files with 559 additions and 557 deletions
|
@ -31,19 +31,17 @@ use crate::formatting_contexts::Baselines;
|
||||||
use crate::fragment_tree::{
|
use crate::fragment_tree::{
|
||||||
BoxFragment, CollapsedBlockMargins, Fragment, FragmentFlags, SpecificLayoutInfo,
|
BoxFragment, CollapsedBlockMargins, Fragment, FragmentFlags, SpecificLayoutInfo,
|
||||||
};
|
};
|
||||||
use crate::geom::{AuOrAuto, LazySize, LogicalRect, LogicalSides, LogicalVec2, Size, Sizes};
|
use crate::geom::{AuOrAuto, LogicalRect, LogicalSides, LogicalVec2};
|
||||||
use crate::layout_box_base::CacheableLayoutResult;
|
use crate::layout_box_base::CacheableLayoutResult;
|
||||||
use crate::positioned::{
|
use crate::positioned::{
|
||||||
AbsolutelyPositionedBox, PositioningContext, PositioningContextLength, relative_adjustement,
|
AbsolutelyPositionedBox, PositioningContext, PositioningContextLength, relative_adjustement,
|
||||||
};
|
};
|
||||||
use crate::sizing::{
|
use crate::sizing::{
|
||||||
ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult, IntrinsicSizingMode,
|
ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult, IntrinsicSizingMode,
|
||||||
|
LazySize, Size, SizeConstraint, Sizes,
|
||||||
};
|
};
|
||||||
use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM, LayoutStyle};
|
use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM, LayoutStyle};
|
||||||
use crate::{
|
use crate::{ConstraintSpace, ContainingBlock, ContainingBlockSize, IndefiniteContainingBlock};
|
||||||
ConstraintSpace, ContainingBlock, ContainingBlockSize, IndefiniteContainingBlock,
|
|
||||||
SizeConstraint,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Layout parameters and intermediate results about a flex container,
|
/// Layout parameters and intermediate results about a flex container,
|
||||||
/// grouped to avoid passing around many parameters
|
/// grouped to avoid passing around many parameters
|
||||||
|
|
|
@ -34,17 +34,17 @@ use crate::fragment_tree::{
|
||||||
Fragment, FragmentFlags,
|
Fragment, FragmentFlags,
|
||||||
};
|
};
|
||||||
use crate::geom::{
|
use crate::geom::{
|
||||||
AuOrAuto, LazySize, LogicalRect, LogicalSides, LogicalSides1D, LogicalVec2, PhysicalPoint,
|
AuOrAuto, LogicalRect, LogicalSides, LogicalSides1D, LogicalVec2, PhysicalPoint, PhysicalRect,
|
||||||
PhysicalRect, PhysicalSides, Size, Sizes, ToLogical, ToLogicalWithContainingBlock,
|
PhysicalSides, ToLogical, ToLogicalWithContainingBlock,
|
||||||
};
|
};
|
||||||
use crate::layout_box_base::{CacheableLayoutResult, LayoutBoxBase};
|
use crate::layout_box_base::{CacheableLayoutResult, LayoutBoxBase};
|
||||||
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength};
|
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength};
|
||||||
use crate::sizing::{self, ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
|
use crate::sizing::{
|
||||||
use crate::style_ext::{AspectRatio, ContentBoxSizesAndPBM, LayoutStyle, PaddingBorderMargin};
|
self, ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult, LazySize, Size,
|
||||||
use crate::{
|
SizeConstraint, Sizes,
|
||||||
ConstraintSpace, ContainingBlock, ContainingBlockSize, IndefiniteContainingBlock,
|
|
||||||
SizeConstraint,
|
|
||||||
};
|
};
|
||||||
|
use crate::style_ext::{AspectRatio, ContentBoxSizesAndPBM, LayoutStyle, PaddingBorderMargin};
|
||||||
|
use crate::{ConstraintSpace, ContainingBlock, ContainingBlockSize, IndefiniteContainingBlock};
|
||||||
|
|
||||||
mod construct;
|
mod construct;
|
||||||
pub mod float;
|
pub mod float;
|
||||||
|
|
|
@ -16,13 +16,14 @@ use crate::dom_traversal::{Contents, NodeAndStyleInfo};
|
||||||
use crate::flexbox::FlexContainer;
|
use crate::flexbox::FlexContainer;
|
||||||
use crate::flow::BlockFormattingContext;
|
use crate::flow::BlockFormattingContext;
|
||||||
use crate::fragment_tree::{BaseFragmentInfo, FragmentFlags};
|
use crate::fragment_tree::{BaseFragmentInfo, FragmentFlags};
|
||||||
use crate::geom::LazySize;
|
|
||||||
use crate::layout_box_base::{
|
use crate::layout_box_base::{
|
||||||
CacheableLayoutResult, CacheableLayoutResultAndInputs, LayoutBoxBase,
|
CacheableLayoutResult, CacheableLayoutResultAndInputs, LayoutBoxBase,
|
||||||
};
|
};
|
||||||
use crate::positioned::PositioningContext;
|
use crate::positioned::PositioningContext;
|
||||||
use crate::replaced::ReplacedContents;
|
use crate::replaced::ReplacedContents;
|
||||||
use crate::sizing::{self, ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
|
use crate::sizing::{
|
||||||
|
self, ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult, LazySize,
|
||||||
|
};
|
||||||
use crate::style_ext::{AspectRatio, DisplayInside, LayoutStyle};
|
use crate::style_ext::{AspectRatio, DisplayInside, LayoutStyle};
|
||||||
use crate::table::Table;
|
use crate::table::Table;
|
||||||
use crate::taffy::TaffyContainer;
|
use crate::taffy::TaffyContainer;
|
||||||
|
|
|
@ -2,24 +2,20 @@
|
||||||
* 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, OnceCell};
|
|
||||||
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};
|
||||||
|
|
||||||
use app_units::{Au, MAX_AU};
|
use app_units::Au;
|
||||||
use malloc_size_of_derive::MallocSizeOf;
|
use malloc_size_of_derive::MallocSizeOf;
|
||||||
use style::Zero;
|
use style::Zero;
|
||||||
use style::logical_geometry::{BlockFlowDirection, Direction, InlineBaseDirection, WritingMode};
|
use style::logical_geometry::{BlockFlowDirection, InlineBaseDirection, WritingMode};
|
||||||
use style::values::computed::{
|
use style::values::computed::{CSSPixelLength, LengthPercentage};
|
||||||
CSSPixelLength, LengthPercentage, MaxSize as StyleMaxSize, Percentage, Size as StyleSize,
|
|
||||||
};
|
|
||||||
use style::values::generics::length::GenericLengthPercentageOrAuto as AutoOr;
|
use style::values::generics::length::GenericLengthPercentageOrAuto as AutoOr;
|
||||||
use style_traits::CSSPixel;
|
use style_traits::CSSPixel;
|
||||||
|
|
||||||
use crate::ContainingBlock;
|
use crate::ContainingBlock;
|
||||||
use crate::sizing::ContentSizes;
|
use crate::sizing::Size;
|
||||||
use crate::style_ext::Clamp;
|
|
||||||
|
|
||||||
pub type PhysicalPoint<U> = euclid::Point2D<U, CSSPixel>;
|
pub type PhysicalPoint<U> = euclid::Point2D<U, CSSPixel>;
|
||||||
pub type PhysicalSize<U> = euclid::Size2D<U, CSSPixel>;
|
pub type PhysicalSize<U> = euclid::Size2D<U, CSSPixel>;
|
||||||
|
@ -686,517 +682,3 @@ impl ToLogicalWithContainingBlock<LogicalRect<Au>> for PhysicalRect<Au> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The possible values accepted by the sizing properties.
|
|
||||||
/// <https://drafts.csswg.org/css-sizing/#sizing-properties>
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub(crate) enum Size<T> {
|
|
||||||
/// Represents an `auto` value for the preferred and minimum size properties,
|
|
||||||
/// or `none` for the maximum size properties.
|
|
||||||
/// <https://drafts.csswg.org/css-sizing/#valdef-width-auto>
|
|
||||||
/// <https://drafts.csswg.org/css-sizing/#valdef-max-width-none>
|
|
||||||
Initial,
|
|
||||||
/// <https://drafts.csswg.org/css-sizing/#valdef-width-min-content>
|
|
||||||
MinContent,
|
|
||||||
/// <https://drafts.csswg.org/css-sizing/#valdef-width-max-content>
|
|
||||||
MaxContent,
|
|
||||||
/// <https://drafts.csswg.org/css-sizing-4/#valdef-width-fit-content>
|
|
||||||
FitContent,
|
|
||||||
/// <https://drafts.csswg.org/css-sizing-3/#funcdef-width-fit-content>
|
|
||||||
FitContentFunction(T),
|
|
||||||
/// <https://drafts.csswg.org/css-sizing-4/#valdef-width-stretch>
|
|
||||||
Stretch,
|
|
||||||
/// Represents a numeric `<length-percentage>`, but resolved as a `T`.
|
|
||||||
/// <https://drafts.csswg.org/css-sizing/#valdef-width-length-percentage-0>
|
|
||||||
Numeric(T),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Copy> Copy for Size<T> {}
|
|
||||||
|
|
||||||
impl<T> Default for Size<T> {
|
|
||||||
#[inline]
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Initial
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Size<T> {
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn is_initial(&self) -> bool {
|
|
||||||
matches!(self, Self::Initial)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone> Size<T> {
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn to_numeric(&self) -> Option<T> {
|
|
||||||
match self {
|
|
||||||
Self::Numeric(numeric) => Some(numeric).cloned(),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn map<U>(&self, f: impl FnOnce(T) -> U) -> Size<U> {
|
|
||||||
match self {
|
|
||||||
Size::Initial => Size::Initial,
|
|
||||||
Size::MinContent => Size::MinContent,
|
|
||||||
Size::MaxContent => Size::MaxContent,
|
|
||||||
Size::FitContent => Size::FitContent,
|
|
||||||
Size::FitContentFunction(size) => Size::FitContentFunction(f(size.clone())),
|
|
||||||
Size::Stretch => Size::Stretch,
|
|
||||||
Size::Numeric(numeric) => Size::Numeric(f(numeric.clone())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<StyleSize> for Size<LengthPercentage> {
|
|
||||||
fn from(size: StyleSize) -> Self {
|
|
||||||
match size {
|
|
||||||
StyleSize::LengthPercentage(lp) => Size::Numeric(lp.0),
|
|
||||||
StyleSize::Auto => Size::Initial,
|
|
||||||
StyleSize::MinContent => Size::MinContent,
|
|
||||||
StyleSize::MaxContent => Size::MaxContent,
|
|
||||||
StyleSize::FitContent => Size::FitContent,
|
|
||||||
StyleSize::FitContentFunction(lp) => Size::FitContentFunction(lp.0),
|
|
||||||
StyleSize::Stretch => Size::Stretch,
|
|
||||||
StyleSize::AnchorSizeFunction(_) | StyleSize::AnchorContainingCalcFunction(_) => {
|
|
||||||
unreachable!("anchor-size() should be disabled")
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<StyleMaxSize> for Size<LengthPercentage> {
|
|
||||||
fn from(max_size: StyleMaxSize) -> Self {
|
|
||||||
match max_size {
|
|
||||||
StyleMaxSize::LengthPercentage(lp) => Size::Numeric(lp.0),
|
|
||||||
StyleMaxSize::None => Size::Initial,
|
|
||||||
StyleMaxSize::MinContent => Size::MinContent,
|
|
||||||
StyleMaxSize::MaxContent => Size::MaxContent,
|
|
||||||
StyleMaxSize::FitContent => Size::FitContent,
|
|
||||||
StyleMaxSize::FitContentFunction(lp) => Size::FitContentFunction(lp.0),
|
|
||||||
StyleMaxSize::Stretch => Size::Stretch,
|
|
||||||
StyleMaxSize::AnchorSizeFunction(_) | StyleMaxSize::AnchorContainingCalcFunction(_) => {
|
|
||||||
unreachable!("anchor-size() should be disabled")
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Size<LengthPercentage> {
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn to_percentage(&self) -> Option<Percentage> {
|
|
||||||
self.to_numeric()
|
|
||||||
.and_then(|length_percentage| length_percentage.to_percentage())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resolves percentages in a preferred size, against the provided basis.
|
|
||||||
/// If the basis is missing, percentages are considered cyclic.
|
|
||||||
/// <https://www.w3.org/TR/css-sizing-3/#preferred-size-properties>
|
|
||||||
/// <https://www.w3.org/TR/css-sizing-3/#cyclic-percentage-size>
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn resolve_percentages_for_preferred(&self, basis: Option<Au>) -> Size<Au> {
|
|
||||||
match self {
|
|
||||||
Size::Numeric(numeric) => numeric
|
|
||||||
.maybe_to_used_value(basis)
|
|
||||||
.map_or(Size::Initial, Size::Numeric),
|
|
||||||
Size::FitContentFunction(numeric) => {
|
|
||||||
// Under discussion in https://github.com/w3c/csswg-drafts/issues/11805
|
|
||||||
numeric
|
|
||||||
.maybe_to_used_value(basis)
|
|
||||||
.map_or(Size::FitContent, Size::FitContentFunction)
|
|
||||||
},
|
|
||||||
_ => self.map(|_| unreachable!("This shouldn't be called for keywords")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resolves percentages in a maximum size, against the provided basis.
|
|
||||||
/// If the basis is missing, percentages are considered cyclic.
|
|
||||||
/// <https://www.w3.org/TR/css-sizing-3/#preferred-size-properties>
|
|
||||||
/// <https://www.w3.org/TR/css-sizing-3/#cyclic-percentage-size>
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn resolve_percentages_for_max(&self, basis: Option<Au>) -> Size<Au> {
|
|
||||||
match self {
|
|
||||||
Size::Numeric(numeric) => numeric
|
|
||||||
.maybe_to_used_value(basis)
|
|
||||||
.map_or(Size::Initial, Size::Numeric),
|
|
||||||
Size::FitContentFunction(numeric) => {
|
|
||||||
// Under discussion in https://github.com/w3c/csswg-drafts/issues/11805
|
|
||||||
numeric
|
|
||||||
.maybe_to_used_value(basis)
|
|
||||||
.map_or(Size::MaxContent, Size::FitContentFunction)
|
|
||||||
},
|
|
||||||
_ => self.map(|_| unreachable!("This shouldn't be called for keywords")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LogicalVec2<Size<LengthPercentage>> {
|
|
||||||
pub(crate) fn percentages_relative_to_basis(
|
|
||||||
&self,
|
|
||||||
basis: &LogicalVec2<Au>,
|
|
||||||
) -> LogicalVec2<Size<Au>> {
|
|
||||||
LogicalVec2 {
|
|
||||||
inline: self.inline.map(|value| value.to_used_value(basis.inline)),
|
|
||||||
block: self.block.map(|value| value.to_used_value(basis.block)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Size<Au> {
|
|
||||||
/// Resolves a preferred size into a numerical value.
|
|
||||||
/// <https://www.w3.org/TR/css-sizing-3/#preferred-size-properties>
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn resolve_for_preferred<F: FnOnce() -> ContentSizes>(
|
|
||||||
&self,
|
|
||||||
automatic_size: Size<Au>,
|
|
||||||
stretch_size: Option<Au>,
|
|
||||||
content_size: &LazyCell<ContentSizes, F>,
|
|
||||||
) -> Au {
|
|
||||||
match self {
|
|
||||||
Self::Initial => {
|
|
||||||
assert!(!automatic_size.is_initial());
|
|
||||||
automatic_size.resolve_for_preferred(automatic_size, stretch_size, content_size)
|
|
||||||
},
|
|
||||||
Self::MinContent => content_size.min_content,
|
|
||||||
Self::MaxContent => content_size.max_content,
|
|
||||||
Self::FitContentFunction(size) => content_size.shrink_to_fit(*size),
|
|
||||||
Self::FitContent => {
|
|
||||||
content_size.shrink_to_fit(stretch_size.unwrap_or_else(|| content_size.max_content))
|
|
||||||
},
|
|
||||||
Self::Stretch => stretch_size.unwrap_or_else(|| content_size.max_content),
|
|
||||||
Self::Numeric(numeric) => *numeric,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resolves a minimum size into a numerical value.
|
|
||||||
/// <https://www.w3.org/TR/css-sizing-3/#min-size-properties>
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn resolve_for_min<F: FnOnce() -> ContentSizes>(
|
|
||||||
&self,
|
|
||||||
get_automatic_minimum_size: impl FnOnce() -> Au,
|
|
||||||
stretch_size: Option<Au>,
|
|
||||||
content_size: &LazyCell<ContentSizes, F>,
|
|
||||||
is_table: bool,
|
|
||||||
) -> Au {
|
|
||||||
let result = match self {
|
|
||||||
Self::Initial => get_automatic_minimum_size(),
|
|
||||||
Self::MinContent => content_size.min_content,
|
|
||||||
Self::MaxContent => content_size.max_content,
|
|
||||||
Self::FitContentFunction(size) => content_size.shrink_to_fit(*size),
|
|
||||||
Self::FitContent => content_size.shrink_to_fit(stretch_size.unwrap_or_default()),
|
|
||||||
Self::Stretch => stretch_size.unwrap_or_default(),
|
|
||||||
Self::Numeric(numeric) => *numeric,
|
|
||||||
};
|
|
||||||
if is_table {
|
|
||||||
// In addition to the specified minimum, the inline size of a table is forced to be
|
|
||||||
// at least as big as its min-content size.
|
|
||||||
//
|
|
||||||
// Note that if there are collapsed columns, only the inline size of the table grid will
|
|
||||||
// shrink, while the size of the table wrapper (being computed here) won't be affected.
|
|
||||||
// However, collapsed rows should typically affect the block size of the table wrapper,
|
|
||||||
// so it might be wrong to use this function for that case.
|
|
||||||
// This is being discussed in https://github.com/w3c/csswg-drafts/issues/11408
|
|
||||||
result.max(content_size.min_content)
|
|
||||||
} else {
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resolves a maximum size into a numerical value.
|
|
||||||
/// <https://www.w3.org/TR/css-sizing-3/#max-size-properties>
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn resolve_for_max<F: FnOnce() -> ContentSizes>(
|
|
||||||
&self,
|
|
||||||
stretch_size: Option<Au>,
|
|
||||||
content_size: &LazyCell<ContentSizes, F>,
|
|
||||||
) -> Option<Au> {
|
|
||||||
Some(match self {
|
|
||||||
Self::Initial => return None,
|
|
||||||
Self::MinContent => content_size.min_content,
|
|
||||||
Self::MaxContent => content_size.max_content,
|
|
||||||
Self::FitContentFunction(size) => content_size.shrink_to_fit(*size),
|
|
||||||
Self::FitContent => content_size.shrink_to_fit(stretch_size.unwrap_or(MAX_AU)),
|
|
||||||
Self::Stretch => return stretch_size,
|
|
||||||
Self::Numeric(numeric) => *numeric,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tries to resolve an extrinsic size into a numerical value.
|
|
||||||
/// Extrinsic sizes are those based on the context of an element, without regard for its contents.
|
|
||||||
/// <https://drafts.csswg.org/css-sizing-3/#extrinsic>
|
|
||||||
///
|
|
||||||
/// Returns `None` if either:
|
|
||||||
/// - The size is intrinsic.
|
|
||||||
/// - The size is the initial one.
|
|
||||||
/// TODO: should we allow it to behave as `stretch` instead of assuming it's intrinsic?
|
|
||||||
/// - The provided `stretch_size` is `None` but we need its value.
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn maybe_resolve_extrinsic(&self, stretch_size: Option<Au>) -> Option<Au> {
|
|
||||||
match self {
|
|
||||||
Self::Initial |
|
|
||||||
Self::MinContent |
|
|
||||||
Self::MaxContent |
|
|
||||||
Self::FitContent |
|
|
||||||
Self::FitContentFunction(_) => None,
|
|
||||||
Self::Stretch => stretch_size,
|
|
||||||
Self::Numeric(numeric) => Some(*numeric),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents the sizing constraint that the preferred, min and max sizing properties
|
|
||||||
/// impose on one axis.
|
|
||||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)]
|
|
||||||
pub(crate) enum SizeConstraint {
|
|
||||||
/// Represents a definite preferred size, clamped by minimum and maximum sizes (if any).
|
|
||||||
Definite(Au),
|
|
||||||
/// Represents an indefinite preferred size that allows a range of values between
|
|
||||||
/// the first argument (minimum size) and the second one (maximum size).
|
|
||||||
MinMax(Au, Option<Au>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for SizeConstraint {
|
|
||||||
#[inline]
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::MinMax(Au::default(), None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SizeConstraint {
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn new(preferred_size: Option<Au>, min_size: Au, max_size: Option<Au>) -> Self {
|
|
||||||
preferred_size.map_or_else(
|
|
||||||
|| Self::MinMax(min_size, max_size),
|
|
||||||
|size| Self::Definite(size.clamp_between_extremums(min_size, max_size)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn is_definite(self) -> bool {
|
|
||||||
matches!(self, Self::Definite(_))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn to_definite(self) -> Option<Au> {
|
|
||||||
match self {
|
|
||||||
Self::Definite(size) => Some(size),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Option<Au>> for SizeConstraint {
|
|
||||||
fn from(size: Option<Au>) -> Self {
|
|
||||||
size.map(SizeConstraint::Definite).unwrap_or_default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, 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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resolves the three sizes into a single numerical value.
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn resolve(
|
|
||||||
&self,
|
|
||||||
axis: Direction,
|
|
||||||
automatic_size: Size<Au>,
|
|
||||||
get_automatic_minimum_size: impl FnOnce() -> Au,
|
|
||||||
stretch_size: Option<Au>,
|
|
||||||
get_content_size: impl FnOnce() -> ContentSizes,
|
|
||||||
is_table: bool,
|
|
||||||
) -> Au {
|
|
||||||
if is_table && axis == Direction::Block {
|
|
||||||
// The intrinsic block size of a table already takes sizing properties into account,
|
|
||||||
// but it can be a smaller amount if there are collapsed rows.
|
|
||||||
// Therefore, disregard sizing properties and just defer to the intrinsic size.
|
|
||||||
// This is being discussed in https://github.com/w3c/csswg-drafts/issues/11408
|
|
||||||
return get_content_size().max_content;
|
|
||||||
}
|
|
||||||
let (preferred, min, max) = self.resolve_each(
|
|
||||||
automatic_size,
|
|
||||||
get_automatic_minimum_size,
|
|
||||||
stretch_size,
|
|
||||||
get_content_size,
|
|
||||||
is_table,
|
|
||||||
);
|
|
||||||
preferred.clamp_between_extremums(min, max)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resolves each of the three sizes into a numerical value, separately.
|
|
||||||
/// - The 1st returned value is the resolved preferred size.
|
|
||||||
/// - The 2nd returned value is the resolved minimum size.
|
|
||||||
/// - The 3rd returned value is the resolved maximum size. `None` means no maximum.
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn resolve_each(
|
|
||||||
&self,
|
|
||||||
automatic_size: Size<Au>,
|
|
||||||
get_automatic_minimum_size: impl FnOnce() -> Au,
|
|
||||||
stretch_size: Option<Au>,
|
|
||||||
get_content_size: impl FnOnce() -> ContentSizes,
|
|
||||||
is_table: bool,
|
|
||||||
) -> (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_for_preferred(automatic_size, stretch_size, &content_size),
|
|
||||||
self.min.resolve_for_min(
|
|
||||||
get_automatic_minimum_size,
|
|
||||||
stretch_size,
|
|
||||||
&content_size,
|
|
||||||
is_table,
|
|
||||||
),
|
|
||||||
self.max.resolve_for_max(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),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct LazySizeData<'a> {
|
|
||||||
sizes: &'a Sizes,
|
|
||||||
axis: Direction,
|
|
||||||
automatic_size: Size<Au>,
|
|
||||||
get_automatic_minimum_size: fn() -> Au,
|
|
||||||
stretch_size: Option<Au>,
|
|
||||||
is_table: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents a size that can't be fully resolved until the intrinsic size
|
|
||||||
/// is known. This is useful in the block axis, since the intrinsic size
|
|
||||||
/// depends on layout, but the other inputs are known beforehand.
|
|
||||||
pub(crate) struct LazySize<'a> {
|
|
||||||
result: OnceCell<Au>,
|
|
||||||
data: Option<LazySizeData<'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> LazySize<'a> {
|
|
||||||
pub(crate) fn new(
|
|
||||||
sizes: &'a Sizes,
|
|
||||||
axis: Direction,
|
|
||||||
automatic_size: Size<Au>,
|
|
||||||
get_automatic_minimum_size: fn() -> Au,
|
|
||||||
stretch_size: Option<Au>,
|
|
||||||
is_table: bool,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
result: OnceCell::new(),
|
|
||||||
data: Some(LazySizeData {
|
|
||||||
sizes,
|
|
||||||
axis,
|
|
||||||
automatic_size,
|
|
||||||
get_automatic_minimum_size,
|
|
||||||
stretch_size,
|
|
||||||
is_table,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a [`LazySize`] that will resolve to the intrinsic size.
|
|
||||||
/// Should be equivalent to [`LazySize::new()`] with default parameters,
|
|
||||||
/// but avoiding the trouble of getting a reference to a [`Sizes::default()`]
|
|
||||||
/// which lives long enough.
|
|
||||||
///
|
|
||||||
/// TODO: It's not clear what this should do if/when [`LazySize::resolve()`]
|
|
||||||
/// is changed to accept a [`ContentSizes`] as the intrinsic size.
|
|
||||||
pub(crate) fn intrinsic() -> Self {
|
|
||||||
Self {
|
|
||||||
result: OnceCell::new(),
|
|
||||||
data: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resolves the [`LazySize`] into [`Au`], caching the result.
|
|
||||||
/// The argument is a callback that computes the intrinsic size lazily.
|
|
||||||
///
|
|
||||||
/// TODO: The intrinsic size should probably be a [`ContentSizes`] instead of [`Au`].
|
|
||||||
pub(crate) fn resolve(&self, get_content_size: impl FnOnce() -> Au) -> Au {
|
|
||||||
*self.result.get_or_init(|| {
|
|
||||||
let Some(ref data) = self.data else {
|
|
||||||
return get_content_size();
|
|
||||||
};
|
|
||||||
data.sizes.resolve(
|
|
||||||
data.axis,
|
|
||||||
data.automatic_size,
|
|
||||||
data.get_automatic_minimum_size,
|
|
||||||
data.stretch_size,
|
|
||||||
|| get_content_size().into(),
|
|
||||||
data.is_table,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Au> for LazySize<'_> {
|
|
||||||
/// Creates a [`LazySize`] that will resolve to the given [`Au`],
|
|
||||||
/// ignoring the intrinsic size.
|
|
||||||
fn from(value: Au) -> Self {
|
|
||||||
let result = OnceCell::new();
|
|
||||||
result.set(value).unwrap();
|
|
||||||
LazySize { result, data: None }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -13,9 +13,8 @@ use style::properties::ComputedValues;
|
||||||
use crate::context::LayoutContext;
|
use crate::context::LayoutContext;
|
||||||
use crate::formatting_contexts::Baselines;
|
use crate::formatting_contexts::Baselines;
|
||||||
use crate::fragment_tree::{BaseFragmentInfo, CollapsedBlockMargins, Fragment, SpecificLayoutInfo};
|
use crate::fragment_tree::{BaseFragmentInfo, CollapsedBlockMargins, Fragment, SpecificLayoutInfo};
|
||||||
use crate::geom::SizeConstraint;
|
|
||||||
use crate::positioned::PositioningContext;
|
use crate::positioned::PositioningContext;
|
||||||
use crate::sizing::{ComputeInlineContentSizes, InlineContentSizesResult};
|
use crate::sizing::{ComputeInlineContentSizes, InlineContentSizesResult, SizeConstraint};
|
||||||
use crate::{ConstraintSpace, ContainingBlockSize};
|
use crate::{ConstraintSpace, ContainingBlockSize};
|
||||||
|
|
||||||
/// A box tree node that handles containing information about style and the original DOM
|
/// A box tree node that handles containing information about style and the original DOM
|
||||||
|
|
|
@ -42,7 +42,8 @@ use servo_arc::Arc as ServoArc;
|
||||||
use style::logical_geometry::WritingMode;
|
use style::logical_geometry::WritingMode;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
|
|
||||||
use crate::geom::{LogicalVec2, SizeConstraint};
|
use crate::geom::LogicalVec2;
|
||||||
|
use crate::sizing::SizeConstraint;
|
||||||
use crate::style_ext::AspectRatio;
|
use crate::style_ext::AspectRatio;
|
||||||
|
|
||||||
/// At times, a style is "owned" by more than one layout object. For example, text
|
/// At times, a style is "owned" by more than one layout object. For example, text
|
||||||
|
|
|
@ -20,15 +20,16 @@ use crate::dom_traversal::{Contents, NodeAndStyleInfo};
|
||||||
use crate::formatting_contexts::IndependentFormattingContext;
|
use crate::formatting_contexts::IndependentFormattingContext;
|
||||||
use crate::fragment_tree::{BoxFragment, Fragment, FragmentFlags, HoistedSharedFragment};
|
use crate::fragment_tree::{BoxFragment, Fragment, FragmentFlags, HoistedSharedFragment};
|
||||||
use crate::geom::{
|
use crate::geom::{
|
||||||
AuOrAuto, LazySize, LengthPercentageOrAuto, LogicalRect, LogicalSides, LogicalSides1D,
|
AuOrAuto, LengthPercentageOrAuto, LogicalRect, LogicalSides, LogicalSides1D, LogicalVec2,
|
||||||
LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalSize, PhysicalVec, Size,
|
PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalSize, PhysicalVec, ToLogical,
|
||||||
Sizes, ToLogical, ToLogicalWithContainingBlock,
|
ToLogicalWithContainingBlock,
|
||||||
};
|
};
|
||||||
use crate::layout_box_base::{CacheableLayoutResult, LayoutBoxBase};
|
use crate::layout_box_base::{CacheableLayoutResult, LayoutBoxBase};
|
||||||
|
use crate::sizing::{LazySize, Size, SizeConstraint, Sizes};
|
||||||
use crate::style_ext::{Clamp, ComputedValuesExt, ContentBoxSizesAndPBM, DisplayInside};
|
use crate::style_ext::{Clamp, ComputedValuesExt, ContentBoxSizesAndPBM, DisplayInside};
|
||||||
use crate::{
|
use crate::{
|
||||||
ConstraintSpace, ContainingBlock, ContainingBlockSize, DefiniteContainingBlock,
|
ConstraintSpace, ContainingBlock, ContainingBlockSize, DefiniteContainingBlock,
|
||||||
PropagatedBoxTreeData, SizeConstraint,
|
PropagatedBoxTreeData,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, MallocSizeOf)]
|
#[derive(Debug, MallocSizeOf)]
|
||||||
|
|
|
@ -29,11 +29,13 @@ use crate::dom::NodeExt;
|
||||||
use crate::fragment_tree::{
|
use crate::fragment_tree::{
|
||||||
BaseFragmentInfo, CollapsedBlockMargins, Fragment, IFrameFragment, ImageFragment,
|
BaseFragmentInfo, CollapsedBlockMargins, Fragment, IFrameFragment, ImageFragment,
|
||||||
};
|
};
|
||||||
use crate::geom::{LazySize, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize};
|
use crate::geom::{LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize};
|
||||||
use crate::layout_box_base::{CacheableLayoutResult, LayoutBoxBase};
|
use crate::layout_box_base::{CacheableLayoutResult, LayoutBoxBase};
|
||||||
use crate::sizing::{ComputeInlineContentSizes, InlineContentSizesResult};
|
use crate::sizing::{
|
||||||
|
ComputeInlineContentSizes, InlineContentSizesResult, LazySize, SizeConstraint,
|
||||||
|
};
|
||||||
use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, LayoutStyle};
|
use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, LayoutStyle};
|
||||||
use crate::{ConstraintSpace, ContainingBlock, SizeConstraint};
|
use crate::{ConstraintSpace, ContainingBlock};
|
||||||
|
|
||||||
#[derive(Debug, MallocSizeOf)]
|
#[derive(Debug, MallocSizeOf)]
|
||||||
pub(crate) struct ReplacedContents {
|
pub(crate) struct ReplacedContents {
|
||||||
|
|
|
@ -4,17 +4,18 @@
|
||||||
|
|
||||||
//! <https://drafts.csswg.org/css-sizing/>
|
//! <https://drafts.csswg.org/css-sizing/>
|
||||||
|
|
||||||
use std::cell::LazyCell;
|
use std::cell::{LazyCell, OnceCell};
|
||||||
use std::ops::{Add, AddAssign};
|
use std::ops::{Add, AddAssign};
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::{Au, MAX_AU};
|
||||||
use malloc_size_of_derive::MallocSizeOf;
|
use malloc_size_of_derive::MallocSizeOf;
|
||||||
use style::Zero;
|
use style::Zero;
|
||||||
use style::logical_geometry::Direction;
|
use style::logical_geometry::Direction;
|
||||||
use style::values::computed::LengthPercentage;
|
use style::values::computed::{
|
||||||
|
LengthPercentage, MaxSize as StyleMaxSize, Percentage, Size as StyleSize,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::context::LayoutContext;
|
use crate::context::LayoutContext;
|
||||||
use crate::geom::{Size, SizeConstraint};
|
|
||||||
use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM, LayoutStyle};
|
use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM, LayoutStyle};
|
||||||
use crate::{ConstraintSpace, IndefiniteContainingBlock, LogicalVec2};
|
use crate::{ConstraintSpace, IndefiniteContainingBlock, LogicalVec2};
|
||||||
|
|
||||||
|
@ -308,3 +309,517 @@ pub(crate) trait ComputeInlineContentSizes {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The possible values accepted by the sizing properties.
|
||||||
|
/// <https://drafts.csswg.org/css-sizing/#sizing-properties>
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub(crate) enum Size<T> {
|
||||||
|
/// Represents an `auto` value for the preferred and minimum size properties,
|
||||||
|
/// or `none` for the maximum size properties.
|
||||||
|
/// <https://drafts.csswg.org/css-sizing/#valdef-width-auto>
|
||||||
|
/// <https://drafts.csswg.org/css-sizing/#valdef-max-width-none>
|
||||||
|
Initial,
|
||||||
|
/// <https://drafts.csswg.org/css-sizing/#valdef-width-min-content>
|
||||||
|
MinContent,
|
||||||
|
/// <https://drafts.csswg.org/css-sizing/#valdef-width-max-content>
|
||||||
|
MaxContent,
|
||||||
|
/// <https://drafts.csswg.org/css-sizing-4/#valdef-width-fit-content>
|
||||||
|
FitContent,
|
||||||
|
/// <https://drafts.csswg.org/css-sizing-3/#funcdef-width-fit-content>
|
||||||
|
FitContentFunction(T),
|
||||||
|
/// <https://drafts.csswg.org/css-sizing-4/#valdef-width-stretch>
|
||||||
|
Stretch,
|
||||||
|
/// Represents a numeric `<length-percentage>`, but resolved as a `T`.
|
||||||
|
/// <https://drafts.csswg.org/css-sizing/#valdef-width-length-percentage-0>
|
||||||
|
Numeric(T),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Copy> Copy for Size<T> {}
|
||||||
|
|
||||||
|
impl<T> Default for Size<T> {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Initial
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Size<T> {
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn is_initial(&self) -> bool {
|
||||||
|
matches!(self, Self::Initial)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone> Size<T> {
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn to_numeric(&self) -> Option<T> {
|
||||||
|
match self {
|
||||||
|
Self::Numeric(numeric) => Some(numeric).cloned(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn map<U>(&self, f: impl FnOnce(T) -> U) -> Size<U> {
|
||||||
|
match self {
|
||||||
|
Size::Initial => Size::Initial,
|
||||||
|
Size::MinContent => Size::MinContent,
|
||||||
|
Size::MaxContent => Size::MaxContent,
|
||||||
|
Size::FitContent => Size::FitContent,
|
||||||
|
Size::FitContentFunction(size) => Size::FitContentFunction(f(size.clone())),
|
||||||
|
Size::Stretch => Size::Stretch,
|
||||||
|
Size::Numeric(numeric) => Size::Numeric(f(numeric.clone())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<StyleSize> for Size<LengthPercentage> {
|
||||||
|
fn from(size: StyleSize) -> Self {
|
||||||
|
match size {
|
||||||
|
StyleSize::LengthPercentage(lp) => Size::Numeric(lp.0),
|
||||||
|
StyleSize::Auto => Size::Initial,
|
||||||
|
StyleSize::MinContent => Size::MinContent,
|
||||||
|
StyleSize::MaxContent => Size::MaxContent,
|
||||||
|
StyleSize::FitContent => Size::FitContent,
|
||||||
|
StyleSize::FitContentFunction(lp) => Size::FitContentFunction(lp.0),
|
||||||
|
StyleSize::Stretch => Size::Stretch,
|
||||||
|
StyleSize::AnchorSizeFunction(_) | StyleSize::AnchorContainingCalcFunction(_) => {
|
||||||
|
unreachable!("anchor-size() should be disabled")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<StyleMaxSize> for Size<LengthPercentage> {
|
||||||
|
fn from(max_size: StyleMaxSize) -> Self {
|
||||||
|
match max_size {
|
||||||
|
StyleMaxSize::LengthPercentage(lp) => Size::Numeric(lp.0),
|
||||||
|
StyleMaxSize::None => Size::Initial,
|
||||||
|
StyleMaxSize::MinContent => Size::MinContent,
|
||||||
|
StyleMaxSize::MaxContent => Size::MaxContent,
|
||||||
|
StyleMaxSize::FitContent => Size::FitContent,
|
||||||
|
StyleMaxSize::FitContentFunction(lp) => Size::FitContentFunction(lp.0),
|
||||||
|
StyleMaxSize::Stretch => Size::Stretch,
|
||||||
|
StyleMaxSize::AnchorSizeFunction(_) | StyleMaxSize::AnchorContainingCalcFunction(_) => {
|
||||||
|
unreachable!("anchor-size() should be disabled")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Size<LengthPercentage> {
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn to_percentage(&self) -> Option<Percentage> {
|
||||||
|
self.to_numeric()
|
||||||
|
.and_then(|length_percentage| length_percentage.to_percentage())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolves percentages in a preferred size, against the provided basis.
|
||||||
|
/// If the basis is missing, percentages are considered cyclic.
|
||||||
|
/// <https://www.w3.org/TR/css-sizing-3/#preferred-size-properties>
|
||||||
|
/// <https://www.w3.org/TR/css-sizing-3/#cyclic-percentage-size>
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn resolve_percentages_for_preferred(&self, basis: Option<Au>) -> Size<Au> {
|
||||||
|
match self {
|
||||||
|
Size::Numeric(numeric) => numeric
|
||||||
|
.maybe_to_used_value(basis)
|
||||||
|
.map_or(Size::Initial, Size::Numeric),
|
||||||
|
Size::FitContentFunction(numeric) => {
|
||||||
|
// Under discussion in https://github.com/w3c/csswg-drafts/issues/11805
|
||||||
|
numeric
|
||||||
|
.maybe_to_used_value(basis)
|
||||||
|
.map_or(Size::FitContent, Size::FitContentFunction)
|
||||||
|
},
|
||||||
|
_ => self.map(|_| unreachable!("This shouldn't be called for keywords")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolves percentages in a maximum size, against the provided basis.
|
||||||
|
/// If the basis is missing, percentages are considered cyclic.
|
||||||
|
/// <https://www.w3.org/TR/css-sizing-3/#preferred-size-properties>
|
||||||
|
/// <https://www.w3.org/TR/css-sizing-3/#cyclic-percentage-size>
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn resolve_percentages_for_max(&self, basis: Option<Au>) -> Size<Au> {
|
||||||
|
match self {
|
||||||
|
Size::Numeric(numeric) => numeric
|
||||||
|
.maybe_to_used_value(basis)
|
||||||
|
.map_or(Size::Initial, Size::Numeric),
|
||||||
|
Size::FitContentFunction(numeric) => {
|
||||||
|
// Under discussion in https://github.com/w3c/csswg-drafts/issues/11805
|
||||||
|
numeric
|
||||||
|
.maybe_to_used_value(basis)
|
||||||
|
.map_or(Size::MaxContent, Size::FitContentFunction)
|
||||||
|
},
|
||||||
|
_ => self.map(|_| unreachable!("This shouldn't be called for keywords")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LogicalVec2<Size<LengthPercentage>> {
|
||||||
|
pub(crate) fn percentages_relative_to_basis(
|
||||||
|
&self,
|
||||||
|
basis: &LogicalVec2<Au>,
|
||||||
|
) -> LogicalVec2<Size<Au>> {
|
||||||
|
LogicalVec2 {
|
||||||
|
inline: self.inline.map(|value| value.to_used_value(basis.inline)),
|
||||||
|
block: self.block.map(|value| value.to_used_value(basis.block)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Size<Au> {
|
||||||
|
/// Resolves a preferred size into a numerical value.
|
||||||
|
/// <https://www.w3.org/TR/css-sizing-3/#preferred-size-properties>
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn resolve_for_preferred<F: FnOnce() -> ContentSizes>(
|
||||||
|
&self,
|
||||||
|
automatic_size: Size<Au>,
|
||||||
|
stretch_size: Option<Au>,
|
||||||
|
content_size: &LazyCell<ContentSizes, F>,
|
||||||
|
) -> Au {
|
||||||
|
match self {
|
||||||
|
Self::Initial => {
|
||||||
|
assert!(!automatic_size.is_initial());
|
||||||
|
automatic_size.resolve_for_preferred(automatic_size, stretch_size, content_size)
|
||||||
|
},
|
||||||
|
Self::MinContent => content_size.min_content,
|
||||||
|
Self::MaxContent => content_size.max_content,
|
||||||
|
Self::FitContentFunction(size) => content_size.shrink_to_fit(*size),
|
||||||
|
Self::FitContent => {
|
||||||
|
content_size.shrink_to_fit(stretch_size.unwrap_or_else(|| content_size.max_content))
|
||||||
|
},
|
||||||
|
Self::Stretch => stretch_size.unwrap_or_else(|| content_size.max_content),
|
||||||
|
Self::Numeric(numeric) => *numeric,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolves a minimum size into a numerical value.
|
||||||
|
/// <https://www.w3.org/TR/css-sizing-3/#min-size-properties>
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn resolve_for_min<F: FnOnce() -> ContentSizes>(
|
||||||
|
&self,
|
||||||
|
get_automatic_minimum_size: impl FnOnce() -> Au,
|
||||||
|
stretch_size: Option<Au>,
|
||||||
|
content_size: &LazyCell<ContentSizes, F>,
|
||||||
|
is_table: bool,
|
||||||
|
) -> Au {
|
||||||
|
let result = match self {
|
||||||
|
Self::Initial => get_automatic_minimum_size(),
|
||||||
|
Self::MinContent => content_size.min_content,
|
||||||
|
Self::MaxContent => content_size.max_content,
|
||||||
|
Self::FitContentFunction(size) => content_size.shrink_to_fit(*size),
|
||||||
|
Self::FitContent => content_size.shrink_to_fit(stretch_size.unwrap_or_default()),
|
||||||
|
Self::Stretch => stretch_size.unwrap_or_default(),
|
||||||
|
Self::Numeric(numeric) => *numeric,
|
||||||
|
};
|
||||||
|
if is_table {
|
||||||
|
// In addition to the specified minimum, the inline size of a table is forced to be
|
||||||
|
// at least as big as its min-content size.
|
||||||
|
//
|
||||||
|
// Note that if there are collapsed columns, only the inline size of the table grid will
|
||||||
|
// shrink, while the size of the table wrapper (being computed here) won't be affected.
|
||||||
|
// However, collapsed rows should typically affect the block size of the table wrapper,
|
||||||
|
// so it might be wrong to use this function for that case.
|
||||||
|
// This is being discussed in https://github.com/w3c/csswg-drafts/issues/11408
|
||||||
|
result.max(content_size.min_content)
|
||||||
|
} else {
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolves a maximum size into a numerical value.
|
||||||
|
/// <https://www.w3.org/TR/css-sizing-3/#max-size-properties>
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn resolve_for_max<F: FnOnce() -> ContentSizes>(
|
||||||
|
&self,
|
||||||
|
stretch_size: Option<Au>,
|
||||||
|
content_size: &LazyCell<ContentSizes, F>,
|
||||||
|
) -> Option<Au> {
|
||||||
|
Some(match self {
|
||||||
|
Self::Initial => return None,
|
||||||
|
Self::MinContent => content_size.min_content,
|
||||||
|
Self::MaxContent => content_size.max_content,
|
||||||
|
Self::FitContentFunction(size) => content_size.shrink_to_fit(*size),
|
||||||
|
Self::FitContent => content_size.shrink_to_fit(stretch_size.unwrap_or(MAX_AU)),
|
||||||
|
Self::Stretch => return stretch_size,
|
||||||
|
Self::Numeric(numeric) => *numeric,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries to resolve an extrinsic size into a numerical value.
|
||||||
|
/// Extrinsic sizes are those based on the context of an element, without regard for its contents.
|
||||||
|
/// <https://drafts.csswg.org/css-sizing-3/#extrinsic>
|
||||||
|
///
|
||||||
|
/// Returns `None` if either:
|
||||||
|
/// - The size is intrinsic.
|
||||||
|
/// - The size is the initial one.
|
||||||
|
/// TODO: should we allow it to behave as `stretch` instead of assuming it's intrinsic?
|
||||||
|
/// - The provided `stretch_size` is `None` but we need its value.
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn maybe_resolve_extrinsic(&self, stretch_size: Option<Au>) -> Option<Au> {
|
||||||
|
match self {
|
||||||
|
Self::Initial |
|
||||||
|
Self::MinContent |
|
||||||
|
Self::MaxContent |
|
||||||
|
Self::FitContent |
|
||||||
|
Self::FitContentFunction(_) => None,
|
||||||
|
Self::Stretch => stretch_size,
|
||||||
|
Self::Numeric(numeric) => Some(*numeric),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents the sizing constraint that the preferred, min and max sizing properties
|
||||||
|
/// impose on one axis.
|
||||||
|
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)]
|
||||||
|
pub(crate) enum SizeConstraint {
|
||||||
|
/// Represents a definite preferred size, clamped by minimum and maximum sizes (if any).
|
||||||
|
Definite(Au),
|
||||||
|
/// Represents an indefinite preferred size that allows a range of values between
|
||||||
|
/// the first argument (minimum size) and the second one (maximum size).
|
||||||
|
MinMax(Au, Option<Au>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SizeConstraint {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::MinMax(Au::default(), None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SizeConstraint {
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn new(preferred_size: Option<Au>, min_size: Au, max_size: Option<Au>) -> Self {
|
||||||
|
preferred_size.map_or_else(
|
||||||
|
|| Self::MinMax(min_size, max_size),
|
||||||
|
|size| Self::Definite(size.clamp_between_extremums(min_size, max_size)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn is_definite(self) -> bool {
|
||||||
|
matches!(self, Self::Definite(_))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn to_definite(self) -> Option<Au> {
|
||||||
|
match self {
|
||||||
|
Self::Definite(size) => Some(size),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Option<Au>> for SizeConstraint {
|
||||||
|
fn from(size: Option<Au>) -> Self {
|
||||||
|
size.map(SizeConstraint::Definite).unwrap_or_default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolves the three sizes into a single numerical value.
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn resolve(
|
||||||
|
&self,
|
||||||
|
axis: Direction,
|
||||||
|
automatic_size: Size<Au>,
|
||||||
|
get_automatic_minimum_size: impl FnOnce() -> Au,
|
||||||
|
stretch_size: Option<Au>,
|
||||||
|
get_content_size: impl FnOnce() -> ContentSizes,
|
||||||
|
is_table: bool,
|
||||||
|
) -> Au {
|
||||||
|
if is_table && axis == Direction::Block {
|
||||||
|
// The intrinsic block size of a table already takes sizing properties into account,
|
||||||
|
// but it can be a smaller amount if there are collapsed rows.
|
||||||
|
// Therefore, disregard sizing properties and just defer to the intrinsic size.
|
||||||
|
// This is being discussed in https://github.com/w3c/csswg-drafts/issues/11408
|
||||||
|
return get_content_size().max_content;
|
||||||
|
}
|
||||||
|
let (preferred, min, max) = self.resolve_each(
|
||||||
|
automatic_size,
|
||||||
|
get_automatic_minimum_size,
|
||||||
|
stretch_size,
|
||||||
|
get_content_size,
|
||||||
|
is_table,
|
||||||
|
);
|
||||||
|
preferred.clamp_between_extremums(min, max)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolves each of the three sizes into a numerical value, separately.
|
||||||
|
/// - The 1st returned value is the resolved preferred size.
|
||||||
|
/// - The 2nd returned value is the resolved minimum size.
|
||||||
|
/// - The 3rd returned value is the resolved maximum size. `None` means no maximum.
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn resolve_each(
|
||||||
|
&self,
|
||||||
|
automatic_size: Size<Au>,
|
||||||
|
get_automatic_minimum_size: impl FnOnce() -> Au,
|
||||||
|
stretch_size: Option<Au>,
|
||||||
|
get_content_size: impl FnOnce() -> ContentSizes,
|
||||||
|
is_table: bool,
|
||||||
|
) -> (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_for_preferred(automatic_size, stretch_size, &content_size),
|
||||||
|
self.min.resolve_for_min(
|
||||||
|
get_automatic_minimum_size,
|
||||||
|
stretch_size,
|
||||||
|
&content_size,
|
||||||
|
is_table,
|
||||||
|
),
|
||||||
|
self.max.resolve_for_max(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),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LazySizeData<'a> {
|
||||||
|
sizes: &'a Sizes,
|
||||||
|
axis: Direction,
|
||||||
|
automatic_size: Size<Au>,
|
||||||
|
get_automatic_minimum_size: fn() -> Au,
|
||||||
|
stretch_size: Option<Au>,
|
||||||
|
is_table: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a size that can't be fully resolved until the intrinsic size
|
||||||
|
/// is known. This is useful in the block axis, since the intrinsic size
|
||||||
|
/// depends on layout, but the other inputs are known beforehand.
|
||||||
|
pub(crate) struct LazySize<'a> {
|
||||||
|
result: OnceCell<Au>,
|
||||||
|
data: Option<LazySizeData<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LazySize<'a> {
|
||||||
|
pub(crate) fn new(
|
||||||
|
sizes: &'a Sizes,
|
||||||
|
axis: Direction,
|
||||||
|
automatic_size: Size<Au>,
|
||||||
|
get_automatic_minimum_size: fn() -> Au,
|
||||||
|
stretch_size: Option<Au>,
|
||||||
|
is_table: bool,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
result: OnceCell::new(),
|
||||||
|
data: Some(LazySizeData {
|
||||||
|
sizes,
|
||||||
|
axis,
|
||||||
|
automatic_size,
|
||||||
|
get_automatic_minimum_size,
|
||||||
|
stretch_size,
|
||||||
|
is_table,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a [`LazySize`] that will resolve to the intrinsic size.
|
||||||
|
/// Should be equivalent to [`LazySize::new()`] with default parameters,
|
||||||
|
/// but avoiding the trouble of getting a reference to a [`Sizes::default()`]
|
||||||
|
/// which lives long enough.
|
||||||
|
///
|
||||||
|
/// TODO: It's not clear what this should do if/when [`LazySize::resolve()`]
|
||||||
|
/// is changed to accept a [`ContentSizes`] as the intrinsic size.
|
||||||
|
pub(crate) fn intrinsic() -> Self {
|
||||||
|
Self {
|
||||||
|
result: OnceCell::new(),
|
||||||
|
data: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolves the [`LazySize`] into [`Au`], caching the result.
|
||||||
|
/// The argument is a callback that computes the intrinsic size lazily.
|
||||||
|
///
|
||||||
|
/// TODO: The intrinsic size should probably be a [`ContentSizes`] instead of [`Au`].
|
||||||
|
pub(crate) fn resolve(&self, get_content_size: impl FnOnce() -> Au) -> Au {
|
||||||
|
*self.result.get_or_init(|| {
|
||||||
|
let Some(ref data) = self.data else {
|
||||||
|
return get_content_size();
|
||||||
|
};
|
||||||
|
data.sizes.resolve(
|
||||||
|
data.axis,
|
||||||
|
data.automatic_size,
|
||||||
|
data.get_automatic_minimum_size,
|
||||||
|
data.stretch_size,
|
||||||
|
|| get_content_size().into(),
|
||||||
|
data.is_table,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Au> for LazySize<'_> {
|
||||||
|
/// Creates a [`LazySize`] that will resolve to the given [`Au`],
|
||||||
|
/// ignoring the intrinsic size.
|
||||||
|
fn from(value: Au) -> Self {
|
||||||
|
let result = OnceCell::new();
|
||||||
|
result.set(value).unwrap();
|
||||||
|
LazySize { result, data: None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -36,8 +36,9 @@ use crate::dom_traversal::{Contents, NonReplacedContents};
|
||||||
use crate::fragment_tree::FragmentFlags;
|
use crate::fragment_tree::FragmentFlags;
|
||||||
use crate::geom::{
|
use crate::geom::{
|
||||||
AuOrAuto, LengthPercentageOrAuto, LogicalSides, LogicalSides1D, LogicalVec2, PhysicalSides,
|
AuOrAuto, LengthPercentageOrAuto, LogicalSides, LogicalSides1D, LogicalVec2, PhysicalSides,
|
||||||
PhysicalSize, Size, Sizes,
|
PhysicalSize,
|
||||||
};
|
};
|
||||||
|
use crate::sizing::{Size, Sizes};
|
||||||
use crate::table::TableLayoutStyle;
|
use crate::table::TableLayoutStyle;
|
||||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
||||||
|
|
||||||
|
|
|
@ -37,11 +37,13 @@ use crate::fragment_tree::{
|
||||||
};
|
};
|
||||||
use crate::geom::{
|
use crate::geom::{
|
||||||
LogicalRect, LogicalSides, LogicalSides1D, LogicalVec2, PhysicalPoint, PhysicalRect,
|
LogicalRect, LogicalSides, LogicalSides1D, LogicalVec2, PhysicalPoint, PhysicalRect,
|
||||||
PhysicalSides, PhysicalVec, Size, SizeConstraint, ToLogical, ToLogicalWithContainingBlock,
|
PhysicalSides, PhysicalVec, ToLogical, ToLogicalWithContainingBlock,
|
||||||
};
|
};
|
||||||
use crate::layout_box_base::CacheableLayoutResult;
|
use crate::layout_box_base::CacheableLayoutResult;
|
||||||
use crate::positioned::{PositioningContext, PositioningContextLength, relative_adjustement};
|
use crate::positioned::{PositioningContext, PositioningContextLength, relative_adjustement};
|
||||||
use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
|
use crate::sizing::{
|
||||||
|
ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult, Size, SizeConstraint,
|
||||||
|
};
|
||||||
use crate::style_ext::{
|
use crate::style_ext::{
|
||||||
BorderStyleColor, Clamp, ComputedValuesExt, LayoutStyle, PaddingBorderMargin,
|
BorderStyleColor, Clamp, ComputedValuesExt, LayoutStyle, PaddingBorderMargin,
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,12 +20,12 @@ use crate::formatting_contexts::{Baselines, IndependentFormattingContext};
|
||||||
use crate::fragment_tree::{
|
use crate::fragment_tree::{
|
||||||
BoxFragment, CollapsedBlockMargins, Fragment, FragmentFlags, SpecificLayoutInfo,
|
BoxFragment, CollapsedBlockMargins, Fragment, FragmentFlags, SpecificLayoutInfo,
|
||||||
};
|
};
|
||||||
use crate::geom::{
|
use crate::geom::{LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalSize};
|
||||||
LazySize, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides, PhysicalSize, SizeConstraint,
|
|
||||||
};
|
|
||||||
use crate::layout_box_base::CacheableLayoutResult;
|
use crate::layout_box_base::CacheableLayoutResult;
|
||||||
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength};
|
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength};
|
||||||
use crate::sizing::{ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult};
|
use crate::sizing::{
|
||||||
|
ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult, LazySize, SizeConstraint,
|
||||||
|
};
|
||||||
use crate::style_ext::LayoutStyle;
|
use crate::style_ext::LayoutStyle;
|
||||||
use crate::{ConstraintSpace, ContainingBlock, ContainingBlockSize};
|
use crate::{ConstraintSpace, ContainingBlock, ContainingBlockSize};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue