diff --git a/Libraries/LibWeb/Rust/src/layout/flex_formatting_context.rs b/Libraries/LibWeb/Rust/src/layout/flex_formatting_context.rs index ec9a2d0453bce..8f64fc2a5d58e 100644 --- a/Libraries/LibWeb/Rust/src/layout/flex_formatting_context.rs +++ b/Libraries/LibWeb/Rust/src/layout/flex_formatting_context.rs @@ -865,13 +865,35 @@ impl<'pass> FlexFormattingContext<'pass> { } fn calculate_min_content_inline_size(&self, index: usize) -> CssPixels { - self.sizing() - .calculate_min_content_inline_size(self.flex_items[index].box_, self.item_containing_block_constraints()) + let sizing = self.sizing(); + let node = self.flex_items[index].box_; + let constraints = self.item_containing_block_constraints(); + let used = self.item_used(index); + if used.has_definite_block_size() { + sizing.calculate_min_content_inline_size_at_definite_block_size( + node, + constraints, + used.content_block_size.get(), + ) + } else { + sizing.calculate_min_content_inline_size(node, constraints) + } } fn calculate_max_content_inline_size(&self, index: usize) -> CssPixels { - self.sizing() - .calculate_max_content_inline_size(self.flex_items[index].box_, self.item_containing_block_constraints()) + let sizing = self.sizing(); + let node = self.flex_items[index].box_; + let constraints = self.item_containing_block_constraints(); + let used = self.item_used(index); + if used.has_definite_block_size() { + sizing.calculate_max_content_inline_size_at_definite_block_size( + node, + constraints, + used.content_block_size.get(), + ) + } else { + sizing.calculate_max_content_inline_size(node, constraints) + } } fn calculate_min_content_block_size(&self, index: usize, inline_size: CssPixels) -> CssPixels { diff --git a/Libraries/LibWeb/Rust/src/layout/formatting_context.rs b/Libraries/LibWeb/Rust/src/layout/formatting_context.rs index 3a257701a3372..44c5464969063 100644 --- a/Libraries/LibWeb/Rust/src/layout/formatting_context.rs +++ b/Libraries/LibWeb/Rust/src/layout/formatting_context.rs @@ -203,10 +203,12 @@ impl MeasurementState { fn cache_key( measured_at_inline_size: Option, + measured_at_block_size: Option, constraints: ContainingBlockConstraints, ) -> IntrinsicSizeCacheKey { IntrinsicSizeCacheKey { measured_at_inline_size, + measured_at_block_size, percentage_basis_inline_size: constraints.percentage_basis_inline_size, percentage_basis_block_size: constraints.percentage_basis_block_size, quirks_mode_percentage_basis_block_size: constraints.quirks_mode_percentage_basis_block_size, diff --git a/Libraries/LibWeb/Rust/src/layout/layout_node_arena.rs b/Libraries/LibWeb/Rust/src/layout/layout_node_arena.rs index b48e97e5085d7..e7fff8a7e34ae 100644 --- a/Libraries/LibWeb/Rust/src/layout/layout_node_arena.rs +++ b/Libraries/LibWeb/Rust/src/layout/layout_node_arena.rs @@ -24,6 +24,7 @@ pub(crate) const SLOTS_PER_CHUNK: usize = 256; #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub(crate) struct IntrinsicSizeCacheKey { pub(crate) measured_at_inline_size: Option, + pub(crate) measured_at_block_size: Option, pub(crate) percentage_basis_inline_size: Option, pub(crate) percentage_basis_block_size: Option, pub(crate) quirks_mode_percentage_basis_block_size: Option, @@ -42,6 +43,7 @@ impl Hash for IntrinsicSizeCacheKey { } hash_optional(self.measured_at_inline_size, state); + hash_optional(self.measured_at_block_size, state); hash_optional(self.percentage_basis_inline_size, state); hash_optional(self.percentage_basis_block_size, state); hash_optional(self.quirks_mode_percentage_basis_block_size, state); diff --git a/Libraries/LibWeb/Rust/src/layout/sizing_context.rs b/Libraries/LibWeb/Rust/src/layout/sizing_context.rs index c5e17d92bd250..7f8c611a6bec7 100644 --- a/Libraries/LibWeb/Rust/src/layout/sizing_context.rs +++ b/Libraries/LibWeb/Rust/src/layout/sizing_context.rs @@ -1169,7 +1169,7 @@ impl SizingContext { self.intrinsic_inline_measurement_cache_get( node, IntrinsicSizeCacheKind::MaxContentInline, - cache_key(None, constraints), + cache_key(None, None, constraints), )? .min_content_inline_size_from_max_content_layout? } else { @@ -1322,7 +1322,11 @@ impl SizingContext { AvailableSize::MaxContent => IntrinsicSizeCacheKind::MaxContentInline, AvailableSize::Definite(_) | AvailableSize::Indefinite => return None, }; - let measurement = self.intrinsic_inline_measurement_cache_get(node, kind, cache_key(None, constraints))?; + let measurement = self.intrinsic_inline_measurement_cache_get( + node, + kind, + cache_key(None, None, constraints), + )?; if measurement.available_block_size != available_block_size { return None; } @@ -1383,6 +1387,24 @@ impl SizingContext { &self, node: Node, constraints: ContainingBlockConstraints, + ) -> CssPixels { + self.calculate_min_content_inline_size_with_block_size(node, constraints, None) + } + + pub(crate) fn calculate_min_content_inline_size_at_definite_block_size( + &self, + node: Node, + constraints: ContainingBlockConstraints, + block_size: CssPixels, + ) -> CssPixels { + self.calculate_min_content_inline_size_with_block_size(node, constraints, Some(block_size)) + } + + fn calculate_min_content_inline_size_with_block_size( + &self, + node: Node, + constraints: ContainingBlockConstraints, + block_size: Option, ) -> CssPixels { let facts = self.facts(node); let style = self.style(node); @@ -1432,25 +1454,26 @@ impl SizingContext { if let Some(cached) = self.intrinsic_inline_measurement_cache_get( node, IntrinsicSizeCacheKind::MinContentInline, - cache_key(None, constraints), + cache_key(None, block_size, constraints), ) { return cached.automatic_content_inline_size; } - if let Some(min_content_inline_size) = self.paired_min_content_inline_size(node, constraints) { + if let Some(min_content_inline_size) = self.paired_min_content_inline_size(node, constraints, block_size) { return min_content_inline_size; } - self.measure_intrinsic_inline_size(node, constraints, IntrinsicSizeCacheKind::MinContentInline) + self.measure_intrinsic_inline_size(node, constraints, block_size, IntrinsicSizeCacheKind::MinContentInline) } fn paired_min_content_inline_size( &self, node: Node, constraints: ContainingBlockConstraints, + block_size: Option, ) -> Option { self.intrinsic_inline_measurement_cache_get( node, IntrinsicSizeCacheKind::MaxContentInline, - cache_key(None, constraints), + cache_key(None, block_size, constraints), )? .min_content_inline_size_from_max_content_layout } @@ -1459,6 +1482,24 @@ impl SizingContext { &self, node: Node, constraints: ContainingBlockConstraints, + ) -> CssPixels { + self.calculate_max_content_inline_size_with_block_size(node, constraints, None) + } + + pub(crate) fn calculate_max_content_inline_size_at_definite_block_size( + &self, + node: Node, + constraints: ContainingBlockConstraints, + block_size: CssPixels, + ) -> CssPixels { + self.calculate_max_content_inline_size_with_block_size(node, constraints, Some(block_size)) + } + + fn calculate_max_content_inline_size_with_block_size( + &self, + node: Node, + constraints: ContainingBlockConstraints, + block_size: Option, ) -> CssPixels { let facts = self.facts(node); let style = self.style(node); @@ -1614,7 +1655,7 @@ impl SizingContext { if !self.has_children(node) { return CssPixels::default(); } - self.measure_intrinsic_inline_size(node, constraints, IntrinsicSizeCacheKind::MaxContentInline) + self.measure_intrinsic_inline_size(node, constraints, block_size, IntrinsicSizeCacheKind::MaxContentInline) } // Lays `node` out under an intrinsic inline-size constraint, reusing and populating the measurement cache. @@ -1622,6 +1663,7 @@ impl SizingContext { &self, node: Node, constraints: ContainingBlockConstraints, + block_size: Option, kind: IntrinsicSizeCacheKind, ) -> CssPixels { let (size_constraint, available_inline_size) = match kind { @@ -1629,13 +1671,20 @@ impl SizingContext { IntrinsicSizeCacheKind::MaxContentInline => (SizeConstraint::MaxContent, AvailableSize::MaxContent), _ => unreachable!("inline measurement cache kind must use the inline axis"), }; - let key = cache_key(None, constraints); + let key = cache_key(None, block_size, constraints); if let Some(cached) = self.intrinsic_inline_measurement_cache_get(node, kind, key) { return cached.automatic_content_inline_size; } let measurement = MeasurementState::create(self.callbacks); let root = measurement.create_used_values(node, constraints); + // NB: A parent layout can assign a definite block size that is not present in computed style, + // such as the stretched cross size of a flex item. Preserve it so descendant percentages + // resolve against the same size during intrinsic measurement. + if let Some(block_size) = block_size { + root.set_content_block_size(block_size); + root.has_definite_block_size.set(true); + } root.inline_size_constraint.set(size_constraint); root.has_definite_inline_size.set(false); let block_size = if root.has_definite_block_size() { @@ -1677,7 +1726,7 @@ impl SizingContext { IntrinsicSizeCacheKind::MaxContentBlock => (SizeConstraint::MaxContent, AvailableSize::MaxContent), _ => unreachable!("block size cache kind must use the block axis"), }; - let key = cache_key(Some(inline_size), constraints); + let key = cache_key(Some(inline_size), None, constraints); if let Some(cached) = self.intrinsic_block_cache_get(node, kind, key) { return cached; } diff --git a/Tests/LibWeb/Text/expected/flex-item-intrinsic-width-from-aspect-ratio-child.txt b/Tests/LibWeb/Text/expected/flex-item-intrinsic-width-from-aspect-ratio-child.txt new file mode 100644 index 0000000000000..7437d77eebc7a --- /dev/null +++ b/Tests/LibWeb/Text/expected/flex-item-intrinsic-width-from-aspect-ratio-child.txt @@ -0,0 +1,2 @@ +item width: 400 +child width: 400 diff --git a/Tests/LibWeb/Text/input/flex-item-intrinsic-width-from-aspect-ratio-child.html b/Tests/LibWeb/Text/input/flex-item-intrinsic-width-from-aspect-ratio-child.html new file mode 100644 index 0000000000000..b3b3e85be7745 --- /dev/null +++ b/Tests/LibWeb/Text/input/flex-item-intrinsic-width-from-aspect-ratio-child.html @@ -0,0 +1,33 @@ + + + + + +
+
+
+
+
+