From 0d754f184a5bc6f3e23f7b1c2fbe92b479a25366 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 25 Jul 2026 13:44:20 +0200 Subject: [PATCH] LibWeb: Invalidate viewport-relative lengths nested in math functions Style invalidation on viewport resize only touches elements whose computed values recorded a viewport metric dependency. Lengths resolved by the Rust calc simplification had no way to report that dependency back, so `calc(50vh - 10px)`, `min(50vh, ...)`, `clamp()` and anything reaching them through var() kept their stale pixel values after a resize until something else dirtied the element's style. On sites like YouTube that made a window resize appear to do nothing until a later unrelated invalidation moved everything at once. Carry the resolution context's tracking flag across the FFI boundary so the Rust length absolutization records viewport (and viewport-dependent font metric) resolutions the same way the C++ path does. Adds a test resizing an iframe and checking each construct picks up the new viewport height. --- Libraries/LibWeb/CSS/Length.h | 5 +++ Libraries/LibWeb/CSS/Rust/src/animation.rs | 1 + .../LibWeb/CSS/Rust/src/style_compute.rs | 18 +++++++++ Libraries/LibWeb/CSS/StyleComputeFFI.h | 1 + ...e-length-in-math-function-invalidation.txt | 2 + ...-length-in-math-function-invalidation.html | 38 +++++++++++++++++++ 6 files changed, 65 insertions(+) create mode 100644 Tests/LibWeb/Text/expected/css/viewport-relative-length-in-math-function-invalidation.txt create mode 100644 Tests/LibWeb/Text/input/css/viewport-relative-length-in-math-function-invalidation.html diff --git a/Libraries/LibWeb/CSS/Length.h b/Libraries/LibWeb/CSS/Length.h index dfb82926b596e..22a09fcf8099c 100644 --- a/Libraries/LibWeb/CSS/Length.h +++ b/Libraries/LibWeb/CSS/Length.h @@ -78,6 +78,11 @@ class WEB_API Length { m_did_resolve_viewport_relative_length = &did_resolve_viewport_relative_length; } + [[nodiscard]] bool* viewport_metric_dependency_flag() const + { + return m_did_resolve_viewport_relative_length; + } + void record_viewport_relative_length_resolution() const { if (m_did_resolve_viewport_relative_length) diff --git a/Libraries/LibWeb/CSS/Rust/src/animation.rs b/Libraries/LibWeb/CSS/Rust/src/animation.rs index 95b3f1e1850d5..f869d9e330bec 100644 --- a/Libraries/LibWeb/CSS/Rust/src/animation.rs +++ b/Libraries/LibWeb/CSS/Rust/src/animation.rs @@ -5238,6 +5238,7 @@ fn animation_length_resolution_context( root_font_metrics: font_metrics(&animation_context.root_font_metrics), font_metrics_depend_on_viewport_metrics: animation_context.font_metrics_depend_on_viewport_metrics, root_font_metrics_depend_on_viewport_metrics: animation_context.root_font_metrics_depend_on_viewport_metrics, + resolved_viewport_relative_length: std::ptr::null_mut(), }) } diff --git a/Libraries/LibWeb/CSS/Rust/src/style_compute.rs b/Libraries/LibWeb/CSS/Rust/src/style_compute.rs index 9e966d3564873..4ec552b432ebf 100644 --- a/Libraries/LibWeb/CSS/Rust/src/style_compute.rs +++ b/Libraries/LibWeb/CSS/Rust/src/style_compute.rs @@ -53,6 +53,19 @@ pub struct FfiLengthResolutionContext { pub root_font_metrics: FfiFontMetrics, pub font_metrics_depend_on_viewport_metrics: bool, pub root_font_metrics_depend_on_viewport_metrics: bool, + /// Optional flag owned by Length::ResolutionContext, set to true whenever a + /// resolution here consumed viewport metrics. Callers that report the + /// dependency through their return value may leave this null. + pub resolved_viewport_relative_length: *mut bool, +} + +/// Records a viewport metric dependency on the context's tracking flag, if one is set. +fn record_viewport_relative_length_resolution(context: &FfiLengthResolutionContext) { + if context.resolved_viewport_relative_length.is_null() { + return; + } + // SAFETY: The flag belongs to a Length::ResolutionContext that outlives this call. + unsafe { *context.resolved_viewport_relative_length = true }; } /// Result of absolutizing a length. @@ -251,6 +264,9 @@ fn absolutize_length(value: f64, unit: usize, context: &FfiLengthResolutionConte } else { context.font_metrics_depend_on_viewport_metrics }; + if depends_on_viewport { + record_viewport_relative_length_resolution(context); + } FfiAbsolutizedLength { handled: true, changed: true, @@ -259,6 +275,7 @@ fn absolutize_length(value: f64, unit: usize, context: &FfiLengthResolutionConte } } LengthUnitKind::ViewportRelative { axis } => { + record_viewport_relative_length_resolution(context); let basis = match axis { ViewportAxis::Width => context.viewport_width, ViewportAxis::Height => context.viewport_height, @@ -3840,6 +3857,7 @@ mod tests { }, font_metrics_depend_on_viewport_metrics: false, root_font_metrics_depend_on_viewport_metrics: true, + resolved_viewport_relative_length: std::ptr::null_mut(), } } diff --git a/Libraries/LibWeb/CSS/StyleComputeFFI.h b/Libraries/LibWeb/CSS/StyleComputeFFI.h index cfe28f776fd6d..0e9eabbecce12 100644 --- a/Libraries/LibWeb/CSS/StyleComputeFFI.h +++ b/Libraries/LibWeb/CSS/StyleComputeFFI.h @@ -34,6 +34,7 @@ inline ComputedValuesFFI::FfiLengthResolutionContext to_ffi_length_resolution_co .root_font_metrics = to_ffi_font_metrics(context.root_font_metrics), .font_metrics_depend_on_viewport_metrics = context.font_metrics_depend_on_viewport_metrics, .root_font_metrics_depend_on_viewport_metrics = context.root_font_metrics_depend_on_viewport_metrics, + .resolved_viewport_relative_length = context.viewport_metric_dependency_flag(), }; } diff --git a/Tests/LibWeb/Text/expected/css/viewport-relative-length-in-math-function-invalidation.txt b/Tests/LibWeb/Text/expected/css/viewport-relative-length-in-math-function-invalidation.txt new file mode 100644 index 0000000000000..51751ba6f867a --- /dev/null +++ b/Tests/LibWeb/Text/expected/css/viewport-relative-length-in-math-function-invalidation.txt @@ -0,0 +1,2 @@ +before resize: plain=200 calc=190 min=200 clamp=200 var=190 +after resize: plain=100 calc=90 min=100 clamp=100 var=90 diff --git a/Tests/LibWeb/Text/input/css/viewport-relative-length-in-math-function-invalidation.html b/Tests/LibWeb/Text/input/css/viewport-relative-length-in-math-function-invalidation.html new file mode 100644 index 0000000000000..baa1a41474f6e --- /dev/null +++ b/Tests/LibWeb/Text/input/css/viewport-relative-length-in-math-function-invalidation.html @@ -0,0 +1,38 @@ + + + + +