aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout_2020
diff options
context:
space:
mode:
authorOriol Brufau <obrufau@igalia.com>2024-11-05 14:46:58 +0100
committerGitHub <noreply@github.com>2024-11-05 13:46:58 +0000
commitee7b207f967135c95733439ed9f34c8001cf3122 (patch)
treec65138abe2f117134f06e3ec24be450eceedf424 /components/layout_2020
parent3289e7d84dd6d905099d99751781a66da55fe04e (diff)
downloadservo-ee7b207f967135c95733439ed9f34c8001cf3122.tar.gz
servo-ee7b207f967135c95733439ed9f34c8001cf3122.zip
Implement keyword sizes for replaced elements (#34091)
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Diffstat (limited to 'components/layout_2020')
-rw-r--r--components/layout_2020/flexbox/layout.rs28
-rw-r--r--components/layout_2020/flow/mod.rs7
-rw-r--r--components/layout_2020/positioned.rs2
-rw-r--r--components/layout_2020/replaced.rs196
4 files changed, 151 insertions, 82 deletions
diff --git a/components/layout_2020/flexbox/layout.rs b/components/layout_2020/flexbox/layout.rs
index 5adf9c912f0..1e78f8c6a7e 100644
--- a/components/layout_2020/flexbox/layout.rs
+++ b/components/layout_2020/flexbox/layout.rs
@@ -18,7 +18,7 @@ use style::properties::longhands::box_sizing::computed_value::T as BoxSizing;
use style::properties::longhands::flex_direction::computed_value::T as FlexDirection;
use style::properties::longhands::flex_wrap::computed_value::T as FlexWrap;
use style::properties::ComputedValues;
-use style::values::computed::length::Size;
+use style::values::computed::length::Size as StyleSize;
use style::values::generics::flex::GenericFlexBasis as FlexBasis;
use style::values::generics::length::{GenericLengthPercentageOrAuto, LengthPercentageOrNormal};
use style::values::specified::align::AlignFlags;
@@ -32,7 +32,7 @@ use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
use crate::formatting_contexts::{Baselines, IndependentFormattingContext, IndependentLayout};
use crate::fragment_tree::{BoxFragment, CollapsedBlockMargins, Fragment, FragmentFlags};
-use crate::geom::{AuOrAuto, LogicalRect, LogicalSides, LogicalVec2};
+use crate::geom::{AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, Size};
use crate::positioned::{
relative_adjustement, AbsolutelyPositionedBox, PositioningContext, PositioningContextLength,
};
@@ -1873,11 +1873,16 @@ impl FlexItem<'_> {
containing_block,
&replaced.style,
LogicalVec2 {
- inline: AuOrAuto::LengthPercentage(inline_size),
- block: block_size,
+ inline: Size::Numeric(inline_size),
+ block: block_size.non_auto().map_or(Size::Initial, Size::Numeric),
},
- flex_axis.vec2_to_flow_relative(self.content_min_size),
- flex_axis.vec2_to_flow_relative(self.content_max_size),
+ flex_axis
+ .vec2_to_flow_relative(self.content_min_size)
+ .map(|size| Size::Numeric(*size)),
+ flex_axis
+ .vec2_to_flow_relative(self.content_max_size)
+ .map(|size| size.map_or(Size::Initial, Size::Numeric)),
+ flex_axis.vec2_to_flow_relative(self.pbm_auto_is_zero),
);
let hypothetical_cross_size = flex_axis.vec2_to_flex_relative(size).cross;
@@ -2505,7 +2510,7 @@ impl FlexItemBox {
let used_flex_basis = match &style.get_position().flex_basis {
FlexBasis::Content => FlexBasis::Content,
- FlexBasis::Size(Size::LengthPercentage(length_percentage)) => {
+ FlexBasis::Size(StyleSize::LengthPercentage(length_percentage)) => {
let apply_box_sizing = |length: Au| {
match style.get_position().box_sizing {
BoxSizing::ContentBox => length,
@@ -2678,9 +2683,12 @@ impl FlexItemBox {
.used_size_as_if_inline_element_from_content_box_sizes(
flex_context.containing_block,
&replaced.style,
- content_box_size,
- min_size,
- max_size,
+ content_box_size
+ .map(|size| size.non_auto().map_or(Size::Initial, Size::Numeric)),
+ min_size.map(|size| Size::Numeric(*size)),
+ max_size.map(|size| size.map_or(Size::Initial, Size::Numeric)),
+ padding_border_margin.padding_border_sums +
+ padding_border_margin.margin.auto_is(Au::zero).sum(),
)
.block
},
diff --git a/components/layout_2020/flow/mod.rs b/components/layout_2020/flow/mod.rs
index c03c8445ae8..a3b4deddccf 100644
--- a/components/layout_2020/flow/mod.rs
+++ b/components/layout_2020/flow/mod.rs
@@ -1359,9 +1359,8 @@ fn layout_in_flow_replaced_block_level(
replaced: &ReplacedContent,
mut sequential_layout_state: Option<&mut SequentialLayoutState>,
) -> BoxFragment {
- let content_box_sizes_and_pbm: ContentBoxSizesAndPBMDeprecated = style
- .content_box_sizes_and_padding_border_margin(&containing_block.into())
- .into();
+ let content_box_sizes_and_pbm =
+ style.content_box_sizes_and_padding_border_margin(&containing_block.into());
let pbm = &content_box_sizes_and_pbm.pbm;
let content_size = replaced.used_size_as_if_inline_element(
containing_block,
@@ -2018,7 +2017,7 @@ impl IndependentFormattingContext {
.used_size_as_if_inline_element(
containing_block,
&replaced.style,
- &content_box_sizes_and_pbm.clone().into(),
+ &content_box_sizes_and_pbm,
)
.to_physical_size(container_writing_mode);
let fragments = replaced.contents.make_fragments(
diff --git a/components/layout_2020/positioned.rs b/components/layout_2020/positioned.rs
index 4e2368575f3..100808d012c 100644
--- a/components/layout_2020/positioned.rs
+++ b/components/layout_2020/positioned.rs
@@ -466,7 +466,7 @@ impl HoistedAbsolutelyPositionedBox {
.used_size_as_if_inline_element(
containing_block,
&style,
- &content_box_sizes_and_pbm.into(),
+ &content_box_sizes_and_pbm,
)
.map(|size| Size::Numeric(*size));
(used_size, Default::default(), Default::default())
diff --git a/components/layout_2020/replaced.rs b/components/layout_2020/replaced.rs
index 387ad969cd5..ddccda13e4f 100644
--- a/components/layout_2020/replaced.rs
+++ b/components/layout_2020/replaced.rs
@@ -6,7 +6,7 @@ use std::cell::LazyCell;
use std::fmt;
use std::sync::{Arc, Mutex};
-use app_units::{Au, MAX_AU};
+use app_units::Au;
use base::id::{BrowsingContextId, PipelineId};
use canvas_traits::canvas::{CanvasId, CanvasMsg, FromLayoutMsg};
use data_url::DataUrl;
@@ -28,9 +28,9 @@ use webrender_api::ImageKey;
use crate::context::LayoutContext;
use crate::dom::NodeExt;
use crate::fragment_tree::{BaseFragmentInfo, Fragment, IFrameFragment, ImageFragment};
-use crate::geom::{LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize};
+use crate::geom::{LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize, Size};
use crate::sizing::InlineContentSizesResult;
-use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated};
+use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM};
use crate::{AuOrAuto, ContainingBlock, IndefiniteContainingBlock};
#[derive(Debug, Serialize)]
@@ -444,16 +444,16 @@ impl ReplacedContent {
&self,
containing_block: &ContainingBlock,
style: &ComputedValues,
- content_box_sizes_and_pbm: &ContentBoxSizesAndPBMDeprecated,
+ content_box_sizes_and_pbm: &ContentBoxSizesAndPBM,
) -> LogicalVec2<Au> {
+ let pbm = &content_box_sizes_and_pbm.pbm;
self.used_size_as_if_inline_element_from_content_box_sizes(
containing_block,
style,
content_box_sizes_and_pbm.content_box_size,
- content_box_sizes_and_pbm
- .content_min_box_size
- .auto_is(Au::zero),
+ content_box_sizes_and_pbm.content_min_box_size,
content_box_sizes_and_pbm.content_max_box_size,
+ pbm.padding_border_sums + pbm.margin.auto_is(Au::zero).sum(),
)
}
@@ -476,76 +476,138 @@ impl ReplacedContent {
///
/// Also used in other cases, for example
/// <https://drafts.csswg.org/css2/visudet.html#block-replaced-width>
+ ///
+ /// The logic differs from CSS2 in order to properly handle `aspect-ratio` and keyword sizes.
+ /// Each axis can have preferred, min and max sizing constraints, plus constraints transferred
+ /// from the other axis if there is an aspect ratio, plus a natural and default size.
+ /// In case of conflict, the order of precedence (from highest to lowest) is:
+ /// 1. Non-transferred min constraint
+ /// 2. Non-transferred max constraint
+ /// 3. Non-transferred preferred constraint
+ /// 4. Transferred min constraint
+ /// 5. Transferred max constraint
+ /// 6. Transferred preferred constraint
+ /// 7. Natural size
+ /// 8. Default object size
+ ///
+ /// <https://drafts.csswg.org/css-sizing-4/#aspect-ratio-size-transfers>
+ /// <https://github.com/w3c/csswg-drafts/issues/6071#issuecomment-2243986313>
pub(crate) fn used_size_as_if_inline_element_from_content_box_sizes(
&self,
containing_block: &ContainingBlock,
style: &ComputedValues,
- box_size: LogicalVec2<AuOrAuto>,
- min_box_size: LogicalVec2<Au>,
- max_box_size: LogicalVec2<Option<Au>>,
+ box_size: LogicalVec2<Size<Au>>,
+ min_box_size: LogicalVec2<Size<Au>>,
+ max_box_size: LogicalVec2<Size<Au>>,
+ pbm_sums: LogicalVec2<Au>,
) -> LogicalVec2<Au> {
- let box_size = box_size.map(|size| size.non_auto());
- let max_box_size = max_box_size.map(|max_size| max_size.unwrap_or(MAX_AU));
+ // <https://drafts.csswg.org/css-sizing-4/#preferred-aspect-ratio>
+ let ratio = self.preferred_aspect_ratio(&containing_block.into(), style);
+
+ // <https://drafts.csswg.org/css-images-3/#natural-dimensions>
+ // <https://drafts.csswg.org/css-images-3/#default-object-size>
let writing_mode = style.writing_mode;
let natural_size = LazyCell::new(|| self.flow_relative_natural_size(writing_mode));
let default_object_size =
LazyCell::new(|| Self::flow_relative_default_object_size(writing_mode));
- let ratio = self.preferred_aspect_ratio(&containing_block.into(), style);
+ let get_inline_fallback_size = || {
+ natural_size
+ .inline
+ .unwrap_or_else(|| default_object_size.inline)
+ };
+ let get_block_fallback_size = || {
+ natural_size
+ .block
+ .unwrap_or_else(|| default_object_size.block)
+ };
- // This is a simplification of the CSS2 algorithm in a way that properly handles `aspect-ratio`.
- // Each axis can have preferred, min and max sizing constraints, plus constraints transferred
- // from the other axis if there is an aspect ratio, plus a natural and default size.
- // In case of conflict, the order of precedence (from highest to lowest) is:
- // 1. Non-transferred min constraint
- // 2. Non-transferred max constraint
- // 3. Non-transferred preferred constraint
- // 4. Transferred min constraint
- // 5. Transferred max constraint
- // 6. Transferred preferred constraint
- // 7. Natural size
- // 8. Default object size
- // <https://drafts.csswg.org/css-sizing-4/#aspect-ratio-size-transfers>
- // <https://github.com/w3c/csswg-drafts/issues/6071#issuecomment-2243986313>
- box_size.map_inline_and_block_axes(
- |inline_size| {
- let mut min = min_box_size.inline;
- let mut max = max_box_size.inline;
- if let Some(ratio) = ratio.filter(|_| inline_size.is_none()) {
- min = ratio
- .compute_dependent_size(Direction::Inline, min_box_size.block)
- .clamp_between_extremums(min, Some(max));
- max.min_assign(
- ratio.compute_dependent_size(Direction::Inline, max_box_size.block),
- );
- }
- inline_size
- .or_else(|| {
- Some(ratio?.compute_dependent_size(Direction::Inline, box_size.block?))
- })
- .or_else(|| natural_size.inline)
- .unwrap_or_else(|| default_object_size.inline)
- .clamp_between_extremums(min, Some(max))
- },
- |block_size| {
- let mut min = min_box_size.block;
- let mut max = max_box_size.block;
- if let Some(ratio) = ratio.filter(|_| block_size.is_none()) {
- min = ratio
- .compute_dependent_size(Direction::Block, min_box_size.inline)
- .clamp_between_extremums(min, Some(max));
- max.min_assign(
- ratio.compute_dependent_size(Direction::Block, max_box_size.inline),
- );
- }
- block_size
- .or_else(|| {
- Some(ratio?.compute_dependent_size(Direction::Block, box_size.inline?))
- })
- .or_else(|| natural_size.block)
- .unwrap_or_else(|| default_object_size.block)
- .clamp_between_extremums(min, Some(max))
- },
- )
+ // <https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing>
+ let inline_stretch_size = Au::zero().max(containing_block.inline_size - pbm_sums.inline);
+ let block_stretch_size = containing_block
+ .block_size
+ .non_auto()
+ .map(|block_size| Au::zero().max(block_size - pbm_sums.block));
+
+ // <https://drafts.csswg.org/css-sizing-3/#intrinsic-sizes>
+ // FIXME: Use ReplacedContent::inline_content_sizes() once it's fixed to correctly handle
+ // min and max constraints.
+ let inline_content_size = LazyCell::new(|| {
+ let Some(ratio) = ratio else {
+ return get_inline_fallback_size();
+ };
+ let block_stretch_size = block_stretch_size.unwrap_or_else(get_block_fallback_size);
+ let transfer = |size| ratio.compute_dependent_size(Direction::Inline, size);
+ let min = transfer(
+ min_box_size
+ .block
+ .maybe_resolve_extrinsic(Some(block_stretch_size))
+ .unwrap_or_default(),
+ );
+ let max = max_box_size
+ .block
+ .maybe_resolve_extrinsic(Some(block_stretch_size))
+ .map(transfer);
+ box_size
+ .block
+ .maybe_resolve_extrinsic(Some(block_stretch_size))
+ .map_or_else(get_inline_fallback_size, transfer)
+ .clamp_between_extremums(min, max)
+ });
+ let block_content_size = LazyCell::new(|| {
+ let Some(ratio) = ratio else {
+ return get_block_fallback_size();
+ };
+ let mut get_inline_content_size = || (*inline_content_size).into();
+ let transfer = |size| ratio.compute_dependent_size(Direction::Block, size);
+ let min = transfer(
+ min_box_size
+ .inline
+ .resolve_non_initial(inline_stretch_size, &mut get_inline_content_size)
+ .unwrap_or_default(),
+ );
+ let max = max_box_size
+ .inline
+ .resolve_non_initial(inline_stretch_size, &mut get_inline_content_size)
+ .map(transfer);
+ box_size
+ .inline
+ .maybe_resolve_extrinsic(Some(inline_stretch_size))
+ .map_or_else(get_block_fallback_size, transfer)
+ .clamp_between_extremums(min, max)
+ });
+ 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);
+
+ // <https://drafts.csswg.org/css-sizing-3/#sizing-properties>
+ 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 min_inline = min_box_size
+ .inline
+ .resolve_non_initial(inline_stretch_size, &mut get_inline_content_size)
+ .unwrap_or_default();
+ let min_block = min_box_size
+ .block
+ .resolve_non_initial(block_stretch_size, &mut get_block_content_size)
+ .unwrap_or_default();
+ let max_inline = max_box_size
+ .inline
+ .resolve_non_initial(inline_stretch_size, &mut get_inline_content_size);
+ let max_block = max_box_size
+ .block
+ .resolve_non_initial(block_stretch_size, &mut get_block_content_size);
+ LogicalVec2 {
+ inline: preferred_inline.clamp_between_extremums(min_inline, max_inline),
+ block: preferred_block.clamp_between_extremums(min_block, max_block),
+ }
}
}