From 6b2d51041691a7d7cf5c38e06ef8c2da16d95d24 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Sat, 11 Jan 2025 13:18:28 +1300 Subject: [PATCH] Special-case "compressible replaced elements" in grid sizing algorithm Signed-off-by: Nico Burns --- src/compute/grid/types/grid_item.rs | 19 ++++++++++++++++++- src/style/mod.rs | 19 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/compute/grid/types/grid_item.rs b/src/compute/grid/types/grid_item.rs index a84c77429..5746303c4 100644 --- a/src/compute/grid/types/grid_item.rs +++ b/src/compute/grid/types/grid_item.rs @@ -28,6 +28,9 @@ pub(in super::super) struct GridItem { /// (in origin-zero coordinates) pub column: Line, + /// Is it a compressible replaced element? + /// https://drafts.csswg.org/css-sizing-3/#min-content-zero + pub is_compressible_replaced: bool, /// The item's overflow style pub overflow: Point, /// The item's box_sizing style @@ -104,6 +107,7 @@ impl GridItem { source_order, row: row_span, column: col_span, + is_compressible_replaced: style.is_compressible_replaced(), overflow: style.overflow(), box_sizing: style.box_sizing(), size: style.size(), @@ -504,7 +508,20 @@ impl GridItem { // Otherwise, the automatic minimum size is zero, as usual. if use_content_based_minimum { - self.min_content_contribution_cached(axis, tree, known_dimensions, inner_node_size) + let mut minimum_contribution = + self.min_content_contribution_cached(axis, tree, known_dimensions, inner_node_size); + + // If the item is a compressible replaced element, and has a definite preferred size or maximum size in the + // relevant axis, the size suggestion is capped by those sizes; for this purpose, any indefinite percentages + // in these sizes are resolved against zero (and considered definite). + if self.is_compressible_replaced { + let size = self.size.get(axis).maybe_resolve(Some(0.0), |val, basis| tree.calc(val, basis)); + let max_size = + self.max_size.get(axis).maybe_resolve(Some(0.0), |val, basis| tree.calc(val, basis)); + minimum_contribution = minimum_contribution.maybe_min(size).maybe_min(max_size); + } + + minimum_contribution } else { 0.0 } diff --git a/src/style/mod.rs b/src/style/mod.rs index e1709ef2a..41cef747a 100644 --- a/src/style/mod.rs +++ b/src/style/mod.rs @@ -54,6 +54,12 @@ pub trait CoreStyle { fn is_block(&self) -> bool { false } + /// Is it a compressible replaced element? + /// https://drafts.csswg.org/css-sizing-3/#min-content-zero + #[inline(always)] + fn is_compressible_replaced(&self) -> bool { + false + } /// Which box do size styles apply to #[inline(always)] fn box_sizing(&self) -> BoxSizing { @@ -338,6 +344,9 @@ pub struct Style { /// Whether a child is display:table or not. This affects children of block layouts. /// This should really be part of `Display`, but it is currently seperate because table layout isn't implemented pub item_is_table: bool, + /// Is it a replaced element like an image or form field? + /// https://drafts.csswg.org/css-sizing-3/#min-content-zero + pub item_is_replaced: bool, /// Should size styles apply to the content box or the border box of the node pub box_sizing: BoxSizing, @@ -465,6 +474,7 @@ impl Style { pub const DEFAULT: Style = Style { display: Display::DEFAULT, item_is_table: false, + item_is_replaced: false, box_sizing: BoxSizing::BorderBox, overflow: Point { x: Overflow::Visible, y: Overflow::Visible }, scrollbar_width: 0.0, @@ -544,6 +554,10 @@ impl CoreStyle for Style { matches!(self.display, Display::Block) } #[inline(always)] + fn is_compressible_replaced(&self) -> bool { + self.item_is_replaced + } + #[inline(always)] fn box_sizing(&self) -> BoxSizing { self.box_sizing } @@ -603,6 +617,10 @@ impl CoreStyle for &'_ T { (*self).is_block() } #[inline(always)] + fn is_compressible_replaced(&self) -> bool { + (*self).is_compressible_replaced() + } + #[inline(always)] fn box_sizing(&self) -> BoxSizing { (*self).box_sizing() } @@ -939,6 +957,7 @@ mod tests { let old_defaults = Style { display: Default::default(), item_is_table: false, + item_is_replaced: false, box_sizing: Default::default(), overflow: Default::default(), scrollbar_width: 0.0,