From 87e044db18dd9171a1e16e6e8debc0d062176c3a Mon Sep 17 00:00:00 2001 From: ldm0 Date: Mon, 19 Oct 2026 02:27:12 +0800 Subject: [PATCH] fix(layout): preserve intrinsic width keywords across inline formatting roles Subtract horizontal margins for explicit inline-block fit-content widths and carry float min/max-content constraints across the IFC boundary. Cover six font-backed role/keyword combinations, including an inline break that exercises the float path. Validation: cargo fmt --all; cargo clippy --workspace --all-targets --all-features -- -D warnings; cargo nextest run --no-fail-fast (20284 passed, 18 skipped). The combined working tree passed these checks before this logical split. Frozen Release and focused browser/WPT validation also passed; final full WPT is running. Original-commit: 00cfb54b45af1087f880c59856c9eba3c4255019 --- moli-layout/src/intrinsic.rs | 2 +- moli-layout/src/taffy_tree.rs | 12 ++++++++- moli/tests/fetch_cli/layout_regressions.rs | 30 ++++++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/moli-layout/src/intrinsic.rs b/moli-layout/src/intrinsic.rs index 6c4d3e1f95..83aa88c0c9 100644 --- a/moli-layout/src/intrinsic.rs +++ b/moli-layout/src/intrinsic.rs @@ -81,7 +81,7 @@ where let preferred_width = layout_box.style.taffy.size.width; let is_replaced = layout_box.is_replaced(); let uses_fit_content = !layout_box.is_replaced() - && layout_box.style.taffy.size.width.is_auto() + && (preferred_width.is_auto() || preferred_width.is_fit_content()) && matches!( layout_box.style.display(), LayoutDisplay::InlineBlock diff --git a/moli-layout/src/taffy_tree.rs b/moli-layout/src/taffy_tree.rs index 498c5baa9a..ac673a63ed 100644 --- a/moli-layout/src/taffy_tree.rs +++ b/moli-layout/src/taffy_tree.rs @@ -2915,10 +2915,20 @@ where // All floats receive the space remaining after horizontal // margins, matching Taffy's block-float parent. Replaced // measurement carries this ownership explicitly. + let available_width = if style.size.width.is_min_content() { + AvailableSpace::MinContent + } else if style.size.width.is_max_content() { + AvailableSpace::MaxContent + } else { + child_inputs + .available_space + .width + .maybe_sub(margin.left + margin.right) + }; let layout_inputs = LayoutInput { available_space: child_inputs .available_space - .map_width(|width| width.maybe_sub(margin.left + margin.right)), + .map_width(|_| available_width), ..child_inputs }; let output = self.compute_child_layout(child.to_taffy(), layout_inputs); diff --git a/moli/tests/fetch_cli/layout_regressions.rs b/moli/tests/fetch_cli/layout_regressions.rs index de167f9607..f6934b287c 100644 --- a/moli/tests/fetch_cli/layout_regressions.rs +++ b/moli/tests/fetch_cli/layout_regressions.rs @@ -184,3 +184,33 @@ fn flex_percentage_padding_keeps_the_text_content_width_before_line_breaking() - } Ok(()) } + +#[test] +fn intrinsic_width_keywords_keep_margin_space_for_float_and_inline_roles() -> Result<()> { + let mut body = String::new(); + for role in ["float", "inline"] { + for (keyword, _) in [ + ("min-content", 46.0), + ("fit-content", 70.0), + ("max-content", 94.0), + ] { + let display = if role == "float" { + "float:left" + } else { + "display:inline-block" + }; + body.push_str(&format!("
aaa bbb

")); + } + } + let value = run_layout(&probe_font_document(&body), GEOMETRY, true)?; + for role in ["float", "inline"] { + for (keyword, width) in [ + ("min-content", 46.0), + ("fit-content", 70.0), + ("max-content", 94.0), + ] { + assert_dimension(&value, &format!("{role}-{keyword}"), "width", width); + } + } + Ok(()) +}