diff options
author | Oriol Brufau <obrufau@igalia.com> | 2024-11-05 14:46:58 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-05 13:46:58 +0000 |
commit | ee7b207f967135c95733439ed9f34c8001cf3122 (patch) | |
tree | c65138abe2f117134f06e3ec24be450eceedf424 /components/layout_2020 | |
parent | 3289e7d84dd6d905099d99751781a66da55fe04e (diff) | |
download | servo-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.rs | 28 | ||||
-rw-r--r-- | components/layout_2020/flow/mod.rs | 7 | ||||
-rw-r--r-- | components/layout_2020/positioned.rs | 2 | ||||
-rw-r--r-- | components/layout_2020/replaced.rs | 196 |
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), + } } } |