fix(geometry): propagate NaN through DOMRect bounds

This commit is contained in:
ldm0
2026-09-09 06:44:46 +08:00
parent 3d4e98da5a
commit 6414934242
4 changed files with 41 additions and 5 deletions
@@ -2513,7 +2513,6 @@ css/geometry/DOMQuad-001.html
css/geometry/DOMQuad-002.html
css/geometry/DOMQuad-nan.html
css/geometry/DOMRect-002.html
css/geometry/DOMRect-nan.html
css/geometry/DOMRectList.html
css/geometry/WebKitCSSMatrix.html
css/geometry/historical.html
@@ -3114,6 +3114,7 @@ css/geometry/DOMMatrix-invert-preserves-2d.html
css/geometry/DOMMatrix-invertSelf.html
css/geometry/DOMMatrix-newobject.html
css/geometry/DOMRect-001.html
css/geometry/DOMRect-nan.html
css/mediaqueries/aspect-ratio-serialization.html
css/mediaqueries/display-mode.html
css/mediaqueries/dynamic-range.html
@@ -421,26 +421,42 @@ fn dom_rect_readonly_attribute_value<'s>(
DomRectReadonlyAttribute::Top => {
let y = dom_rect_slot(object, scope, DOM_RECT_Y_SLOT);
let height = dom_rect_slot(object, scope, DOM_RECT_HEIGHT_SLOT);
y.min(y + height)
dom_rect_min(y, y + height)
}
DomRectReadonlyAttribute::Right => {
let x = dom_rect_slot(object, scope, DOM_RECT_X_SLOT);
let width = dom_rect_slot(object, scope, DOM_RECT_WIDTH_SLOT);
x.max(x + width)
dom_rect_max(x, x + width)
}
DomRectReadonlyAttribute::Bottom => {
let y = dom_rect_slot(object, scope, DOM_RECT_Y_SLOT);
let height = dom_rect_slot(object, scope, DOM_RECT_HEIGHT_SLOT);
y.max(y + height)
dom_rect_max(y, y + height)
}
DomRectReadonlyAttribute::Left => {
let x = dom_rect_slot(object, scope, DOM_RECT_X_SLOT);
let width = dom_rect_slot(object, scope, DOM_RECT_WIDTH_SLOT);
x.min(x + width)
dom_rect_min(x, x + width)
}
}
}
fn dom_rect_min(lhs: f64, rhs: f64) -> f64 {
if lhs.is_nan() || rhs.is_nan() {
f64::NAN
} else {
lhs.min(rhs)
}
}
fn dom_rect_max(lhs: f64, rhs: f64) -> f64 {
if lhs.is_nan() || rhs.is_nan() {
f64::NAN
} else {
lhs.max(rhs)
}
}
fn dom_rect_slot<'s>(
object: v8::Local<'s, v8::Object>,
scope: &mut v8::PinScope<'s, '_>,
@@ -1718,6 +1718,26 @@ fn dom_rect_readonly_is_constructible_and_to_json_uses_the_function_realm() {
);
}
#[test]
fn dom_rect_bounds_propagate_nan_components() {
let mut vm = new_storage_test_vm("https://domrect-nan-bounds.test/");
let result = vm
.eval(
r#"
(() => [DOMRect, DOMRectReadOnly].every(Rect => {
const width = new Rect(0, 0, NaN, 0).toJSON();
const height = new Rect(0, 0, 0, NaN).toJSON();
return Number.isNaN(width.left) && Number.isNaN(width.right) &&
Number.isNaN(height.top) && Number.isNaN(height.bottom);
}))()
"#,
)
.expect("DOMRect NaN bounds should evaluate");
assert_eq!(result, "true");
}
#[test]
fn geometry_domrect_private_slots_ignore_reflection_and_spoofing() {
let mut vm = new_storage_test_vm("https://geometry-domrect-private-slots.test/");