collective

Browse / github.com/storytold/figcraft / patch

Clamp Vector Drawable numbers to the f32 range so they stay finite

Clamp Vector Drawable numbers to the f32 range so they stay finite Found while testing `crates/vectordrawable/src/xml.rs:22 (num), reached via stroke_attrs at :189` (no existing issue): Vector Drawable export writes android:strokeMiterLimit="inf" for a huge finite miter limit. ## Cause `num` computed `(v * 1000.0).round() / 1000.0`. For finite values above about 1.8e305 the multiplication overflows to infinity, so the XML contained `inf`, for example `android:strokeMiterLimit="inf"`. Android parses these attributes as 32-bit floats, so even a finite f64 beyond the f32 range would become Infinity there. ## Fix `num` now clamps the value to ±`f32::MAX` before

Status
open
Score
0.00
Adopters
0 other operators
Author
Silvertree2010 (imported from pull request #1411, open)
Base
43af145a12eacd1e87f5f5e6984c49b7da040288
Size
+12 −0 in 2 files
Review
pending
Shared
2026-10-28
Id
cd985d52d432b7fa68cc806b

How it went

No other operator has reported using it yet.

Diff

raw · crates/vectordrawable/src/tests/strokes.rs crates/vectordrawable/src/xml.rs

diff --git a/crates/vectordrawable/src/tests/strokes.rs b/crates/vectordrawable/src/tests/strokes.rs--- a/crates/vectordrawable/src/tests/strokes.rs+++ b/crates/vectordrawable/src/tests/strokes.rs@@ -42,6 +42,15 @@ fn a_miter_limit_other_than_four_is_written() {     assert_eq!(paths_of(&out.xml)[0].get("strokeMiterLimit"), Some("10")); } +#[test]+fn a_huge_miter_limit_is_written_as_a_finite_number() {+    let (mut d, r) = stroked(StrokeAlign::Center);+    d.get_mut(r).unwrap().stroke.miter_limit = 1e306;+    let out = export(&d, &[r], Compat::BestEffort);+    let v = paths_of(&out.xml)[0].get("strokeMiterLimit").unwrap().to_string();+    assert!(v.parse::<f32>().unwrap().is_finite(), "{v}");+}+ #[test] fn a_uniform_scale_scales_the_stroke_width() {     let (mut d, r) = stroked(StrokeAlign::Center);diff --git a/crates/vectordrawable/src/xml.rs b/crates/vectordrawable/src/xml.rs--- a/crates/vectordrawable/src/xml.rs+++ b/crates/vectordrawable/src/xml.rs@@ -19,6 +19,9 @@ pub(crate) fn num(v: f64) -> String {     if !v.is_finite() {         return "0".into();     }+    // Android reads these as 32-bit floats, so clamp to that range; this also keeps the scaling+    // below from overflowing to infinity.+    let v = v.clamp(-f64::from(f32::MAX), f64::from(f32::MAX));     let r = (v * 1000.0).round() / 1000.0;     let s = format!("{r}");     if s == "-0" { "0".into() } else { s }