diff options
author | Oriol Brufau <obrufau@igalia.com> | 2024-10-30 15:01:47 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-30 14:01:47 +0000 |
commit | 1891c5cfafe5e589d6bf828deb8ea1ad14f70f61 (patch) | |
tree | 4db22112b6dd9e13d737bc51182771f4e0a5c318 /components/layout_2020/replaced.rs | |
parent | f12071f77eef0612c16c0f297c29e95929218576 (diff) | |
download | servo-1891c5cfafe5e589d6bf828deb8ea1ad14f70f61.tar.gz servo-1891c5cfafe5e589d6bf828deb8ea1ad14f70f61.zip |
Properly transfer min/max constraints on auto-sized replaced elements (#34026)
We were following CSS2, which didn't handle `aspect-ratio`.
This patch simplifies the logic and handles it correctly.
Unfortunately this makes 2 tests fail, but I'm pretty sure they aren't
spec-compliant. I'm leaving them as-is for now since they are part of
interop-2021, and Gecko, Blink and WebKit pass them (because of some
non-interoperable incorrect behaviors).
I'm adding a new test that is fully passed by Servo and WebKit.
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
Diffstat (limited to 'components/layout_2020/replaced.rs')
-rw-r--r-- | components/layout_2020/replaced.rs | 145 |
1 files changed, 31 insertions, 114 deletions
diff --git a/components/layout_2020/replaced.rs b/components/layout_2020/replaced.rs index 0f65d30f822..f97093519f6 100644 --- a/components/layout_2020/replaced.rs +++ b/components/layout_2020/replaced.rs @@ -5,7 +5,7 @@ use std::fmt; use std::sync::{Arc, Mutex}; -use app_units::Au; +use app_units::{Au, MAX_AU}; use base::id::{BrowsingContextId, PipelineId}; use canvas_traits::canvas::{CanvasId, CanvasMsg, FromLayoutMsg}; use data_url::DataUrl; @@ -564,119 +564,36 @@ impl ReplacedContent { if let (AuOrAuto::Auto, AuOrAuto::Auto, Some(ratio)) = (box_size.inline, box_size.block, intrinsic_ratio) { - let LogicalVec2 { - inline: inline_size, - block: block_size, - } = get_tentative_size(box_size); - enum Violation { - None, - Below(Au), - Above(Au), - } - let violation = |size: Au, min_size: Au, mut max_size: Option<Au>| { - if let Some(max) = max_size.as_mut() { - max.max_assign(min_size); - } - if size < min_size { - return Violation::Below(min_size); - } - match max_size { - Some(max_size) if size > max_size => Violation::Above(max_size), - _ => Violation::None, - } - }; - return match ( - violation(inline_size, min_box_size.inline, max_box_size.inline), - violation(block_size, min_box_size.block, max_box_size.block), - ) { - // Row 1. - (Violation::None, Violation::None) => LogicalVec2 { - inline: inline_size, - block: block_size, - }, - // Row 2. - (Violation::Above(max_inline_size), Violation::None) => LogicalVec2 { - inline: max_inline_size, - block: ratio - .compute_dependent_size(Direction::Block, max_inline_size) - .max(min_box_size.block), - }, - // Row 3. - (Violation::Below(min_inline_size), Violation::None) => LogicalVec2 { - inline: min_inline_size, - block: ratio - .compute_dependent_size(Direction::Block, min_inline_size) - .clamp_below_max(max_box_size.block), - }, - // Row 4. - (Violation::None, Violation::Above(max_block_size)) => LogicalVec2 { - inline: ratio - .compute_dependent_size(Direction::Inline, max_block_size) - .max(min_box_size.inline), - block: max_block_size, - }, - // Row 5. - (Violation::None, Violation::Below(min_block_size)) => LogicalVec2 { - inline: ratio - .compute_dependent_size(Direction::Inline, min_block_size) - .clamp_below_max(max_box_size.inline), - block: min_block_size, - }, - // Rows 6-7. - (Violation::Above(max_inline_size), Violation::Above(max_block_size)) => { - let transferred_block_size = - ratio.compute_dependent_size(Direction::Block, max_inline_size); - if transferred_block_size <= max_block_size { - // Row 6. - LogicalVec2 { - inline: max_inline_size, - block: transferred_block_size.max(min_box_size.block), - } - } else { - // Row 7. - LogicalVec2 { - inline: ratio - .compute_dependent_size(Direction::Inline, max_block_size) - .max(min_box_size.inline), - block: max_block_size, - } - } - }, - // Rows 8-9. - (Violation::Below(min_inline_size), Violation::Below(min_block_size)) => { - let transferred_inline_size = - ratio.compute_dependent_size(Direction::Inline, min_block_size); - if min_inline_size <= transferred_inline_size { - // Row 8. - LogicalVec2 { - inline: transferred_inline_size.clamp_below_max(max_box_size.inline), - block: min_block_size, - } - } else { - // Row 9. - LogicalVec2 { - inline: min_inline_size, - block: ratio - .compute_dependent_size(Direction::Block, min_inline_size) - .clamp_below_max(max_box_size.block), - } - } - }, - // Row 10. - (Violation::Below(min_inline_size), Violation::Above(max_block_size)) => { - LogicalVec2 { - inline: min_inline_size, - block: max_block_size, - } - }, - // Row 11. - (Violation::Above(max_inline_size), Violation::Below(min_block_size)) => { - LogicalVec2 { - inline: max_inline_size, - block: min_block_size, - } - }, - }; + let tentative_size = get_tentative_size(box_size); + let max_box_size = max_box_size.map(|max_size| max_size.unwrap_or(MAX_AU)); + // This is a simplification of the CSS2 algorithm in a way that properly handles `aspect-ratio`. + // We transfer min and max constraints from the other axis, and apply them in addition to + // non-transferred min and max constraints. In case of conflict, + // - Non-transferred constraints take precedence over transferred ones. + // - Min constraints take precedence over max ones from the same axis. + // <https://drafts.csswg.org/css-sizing-4/#aspect-ratio-size-transfers> + // <https://github.com/w3c/csswg-drafts/issues/6071#issuecomment-2243986313> + let inline = tentative_size.inline.clamp_between_extremums( + ratio + .compute_dependent_size(Direction::Inline, min_box_size.block) + .clamp_between_extremums(min_box_size.inline, Some(max_box_size.inline)), + Some( + ratio + .compute_dependent_size(Direction::Inline, max_box_size.block) + .min(max_box_size.inline), + ), + ); + let block = tentative_size.block.clamp_between_extremums( + ratio + .compute_dependent_size(Direction::Block, min_box_size.inline) + .clamp_between_extremums(min_box_size.block, Some(max_box_size.block)), + Some( + ratio + .compute_dependent_size(Direction::Block, max_box_size.inline) + .min(max_box_size.block), + ), + ); + return LogicalVec2 { inline, block }; } // https://drafts.csswg.org/css2/#min-max-widths "The following algorithm describes how the two properties |