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 { + 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 /// + /// + /// 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 + /// + /// + /// pub(crate) fn used_size_as_if_inline_element_from_content_box_sizes( &self, containing_block: &ContainingBlock, style: &ComputedValues, - box_size: LogicalVec2, - min_box_size: LogicalVec2, - max_box_size: LogicalVec2>, + box_size: LogicalVec2>, + min_box_size: LogicalVec2>, + max_box_size: LogicalVec2>, + pbm_sums: LogicalVec2, ) -> LogicalVec2 { - 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)); + // + let ratio = self.preferred_aspect_ratio(&containing_block.into(), style); + + // + // 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 - // - // - 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)) - }, - ) + // + 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)); + + // + // 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); + + // + 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), + } } } diff --git a/tests/wpt/meta/MANIFEST.json b/tests/wpt/meta/MANIFEST.json index d47a92c7313..e1d6ccfac99 100644 --- a/tests/wpt/meta/MANIFEST.json +++ b/tests/wpt/meta/MANIFEST.json @@ -570980,6 +570980,13 @@ {} ] ], + "keyword-sizes-on-replaced-element.html": [ + "e26c1b7d6ac38858fd7a941a690ea01e6005c38c", + [ + null, + {} + ] + ], "min-max-content-orthogonal-flow-crash-001.html": [ "d2617f8aa2d1c966e394abb1d1617c012ea4648e", [ diff --git a/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-001.html.ini b/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-001.html.ini deleted file mode 100644 index 9584350fcc9..00000000000 --- a/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-001.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[image-min-max-content-intrinsic-size-change-001.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-002.html.ini b/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-002.html.ini deleted file mode 100644 index cf3f37da003..00000000000 --- a/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-002.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[image-min-max-content-intrinsic-size-change-002.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-003.html.ini b/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-003.html.ini deleted file mode 100644 index f8a6c079eb3..00000000000 --- a/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-003.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[image-min-max-content-intrinsic-size-change-003.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-004.html.ini b/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-004.html.ini deleted file mode 100644 index bd8cf6d5aeb..00000000000 --- a/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-004.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[image-min-max-content-intrinsic-size-change-004.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-005.html.ini b/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-005.html.ini deleted file mode 100644 index 642cb65caac..00000000000 --- a/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-005.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[image-min-max-content-intrinsic-size-change-005.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-006.html.ini b/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-006.html.ini deleted file mode 100644 index 53b834e36fe..00000000000 --- a/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-006.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[image-min-max-content-intrinsic-size-change-006.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-007.html.ini b/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-007.html.ini deleted file mode 100644 index 8e4cf87a152..00000000000 --- a/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-007.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[image-min-max-content-intrinsic-size-change-007.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-008.html.ini b/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-008.html.ini deleted file mode 100644 index 6bcf1ccbf77..00000000000 --- a/tests/wpt/meta/css/css-sizing/image-min-max-content-intrinsic-size-change-008.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[image-min-max-content-intrinsic-size-change-008.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-sizing/replaced-max-height-min-content.html.ini b/tests/wpt/meta/css/css-sizing/replaced-max-height-min-content.html.ini deleted file mode 100644 index 1850f3c41c2..00000000000 --- a/tests/wpt/meta/css/css-sizing/replaced-max-height-min-content.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[replaced-max-height-min-content.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-sizing/replaced-max-width-min-content.html.ini b/tests/wpt/meta/css/css-sizing/replaced-max-width-min-content.html.ini deleted file mode 100644 index 70634828627..00000000000 --- a/tests/wpt/meta/css/css-sizing/replaced-max-width-min-content.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[replaced-max-width-min-content.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-sizing/replaced-min-height-min-content.html.ini b/tests/wpt/meta/css/css-sizing/replaced-min-height-min-content.html.ini deleted file mode 100644 index e10292f4a06..00000000000 --- a/tests/wpt/meta/css/css-sizing/replaced-min-height-min-content.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[replaced-min-height-min-content.html] - expected: FAIL diff --git a/tests/wpt/meta/css/css-sizing/replaced-min-width-min-content.html.ini b/tests/wpt/meta/css/css-sizing/replaced-min-width-min-content.html.ini deleted file mode 100644 index acf6d031ca8..00000000000 --- a/tests/wpt/meta/css/css-sizing/replaced-min-width-min-content.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[replaced-min-width-min-content.html] - expected: FAIL diff --git a/tests/wpt/tests/css/css-sizing/keyword-sizes-on-replaced-element.html b/tests/wpt/tests/css/css-sizing/keyword-sizes-on-replaced-element.html new file mode 100644 index 00000000000..e26c1b7d6ac --- /dev/null +++ b/tests/wpt/tests/css/css-sizing/keyword-sizes-on-replaced-element.html @@ -0,0 +1,184 @@ + +Keyword sizes on replaced element + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + +
+ X X + X X + X X + X X + X X + X X +
+ + +
+ + + +
+ + +
+ + + +
+ + + + +