From 13a748b7ea5a4ff77f114bbc7c309d6809ffd57b Mon Sep 17 00:00:00 2001 From: ldm0 Date: Fri, 11 Sep 2026 01:23:22 +0800 Subject: [PATCH] fix(geometry): serialize DOMMatrix numbers like ECMAScript Source-commit: 715995c959a3355da5a2f0e59fe0a179259b130d --- Cargo.lock | 1 + moli-geometry/Cargo.toml | 1 + moli-geometry/src/lib.rs | 19 ++++++ moli-geometry/src/matrix.rs | 58 ++++++++++++------- .../src/context_bootstrap/geometry_runtime.rs | 2 +- 5 files changed, 58 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fdaa7cb9c4..603bb7f806 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2567,6 +2567,7 @@ dependencies = [ name = "moli-geometry" version = "0.1.0" dependencies = [ + "dragonbox_ecma", "moli-css-parse", ] diff --git a/moli-geometry/Cargo.toml b/moli-geometry/Cargo.toml index 50aceb268c..5a50a74004 100644 --- a/moli-geometry/Cargo.toml +++ b/moli-geometry/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" edition = "2024" [dependencies] +dragonbox_ecma = "0.1.12" moli-css-parse = { path = "../moli-css-parse" } [lints] diff --git a/moli-geometry/src/lib.rs b/moli-geometry/src/lib.rs index 4abb232cee..a862390b87 100644 --- a/moli-geometry/src/lib.rs +++ b/moli-geometry/src/lib.rs @@ -17,6 +17,25 @@ mod tests { ); } + #[test] + fn dom_matrix_text_uses_ecmascript_number_serialization() { + for (value, expected) in [ + (1.0 / 300_000_000.0, "3.3333333333333334e-9"), + (f64::MAX, "1.7976931348623157e+308"), + (f64::MIN_POSITIVE * f64::EPSILON, "5e-324"), + ] { + let matrix = DomMatrixComponents { + m42: value, + ..DomMatrixComponents::identity() + }; + + assert_eq!( + matrix.dom_matrix_text().unwrap(), + format!("matrix(1, 0, 0, 1, 0, {expected})") + ); + } + } + #[test] fn parses_css_transform_list_into_product_matrix() { let matrix = parse_dom_matrix_value("translateX(10px) scale(2) rotate(90deg)").unwrap(); diff --git a/moli-geometry/src/matrix.rs b/moli-geometry/src/matrix.rs index 90bf32dfa1..7412c2c865 100644 --- a/moli-geometry/src/matrix.rs +++ b/moli-geometry/src/matrix.rs @@ -498,6 +498,14 @@ impl DomMatrixComponents { } pub fn css_text(self) -> Option { + self.text(css_number) + } + + pub fn dom_matrix_text(self) -> Option { + self.text(ecmascript_number) + } + + fn text(self, serialize_number: fn(f64) -> String) -> Option { if self.is_2d() { let values = [self.m11, self.m12, self.m21, self.m22, self.m41, self.m42]; if !values.iter().all(|value| value.is_finite()) { @@ -505,12 +513,12 @@ impl DomMatrixComponents { } return Some(format!( "matrix({}, {}, {}, {}, {}, {})", - css_number(self.m11), - css_number(self.m12), - css_number(self.m21), - css_number(self.m22), - css_number(self.m41), - css_number(self.m42) + serialize_number(self.m11), + serialize_number(self.m12), + serialize_number(self.m21), + serialize_number(self.m22), + serialize_number(self.m41), + serialize_number(self.m42) )); } @@ -523,26 +531,32 @@ impl DomMatrixComponents { } Some(format!( "matrix3d({}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {})", - css_number(self.m11), - css_number(self.m12), - css_number(self.m13), - css_number(self.m14), - css_number(self.m21), - css_number(self.m22), - css_number(self.m23), - css_number(self.m24), - css_number(self.m31), - css_number(self.m32), - css_number(self.m33), - css_number(self.m34), - css_number(self.m41), - css_number(self.m42), - css_number(self.m43), - css_number(self.m44) + serialize_number(self.m11), + serialize_number(self.m12), + serialize_number(self.m13), + serialize_number(self.m14), + serialize_number(self.m21), + serialize_number(self.m22), + serialize_number(self.m23), + serialize_number(self.m24), + serialize_number(self.m31), + serialize_number(self.m32), + serialize_number(self.m33), + serialize_number(self.m34), + serialize_number(self.m41), + serialize_number(self.m42), + serialize_number(self.m43), + serialize_number(self.m44) )) } } +fn ecmascript_number(value: f64) -> String { + dragonbox_ecma::Buffer::new() + .format_finite(value) + .to_owned() +} + fn css_number(value: f64) -> String { if value == 0.0 { "0".to_owned() diff --git a/moli-renderer-v8/src/context_bootstrap/geometry_runtime.rs b/moli-renderer-v8/src/context_bootstrap/geometry_runtime.rs index 41a764f845..1ff8712120 100644 --- a/moli-renderer-v8/src/context_bootstrap/geometry_runtime.rs +++ b/moli-renderer-v8/src/context_bootstrap/geometry_runtime.rs @@ -1966,7 +1966,7 @@ fn dom_matrix_css_text<'s>( scope: &mut v8::PinScope<'s, '_>, object: v8::Local<'s, v8::Object>, ) -> Option { - let Some(css_text) = dom_matrix_components(scope, object).css_text() else { + let Some(css_text) = dom_matrix_components(scope, object).dom_matrix_text() else { throw_dom_exception( scope, "InvalidStateError",