diff --git a/crates/chart/src/raster.rs b/crates/chart/src/raster.rs index 5da9d35..67ed53e 100644 --- a/crates/chart/src/raster.rs +++ b/crates/chart/src/raster.rs @@ -138,7 +138,8 @@ fn circle(cx: f32, cy: f32, r: f32) -> Vec<[f32; 2]> { } fn rounded_rect(x: f32, y: f32, w: f32, h: f32, r: f32) -> Vec<[f32; 2]> { - let r = r.clamp(0.0, w.min(h) / 2.0); + // A negative or NaN extent gives an upper bound of 0 (clamp panics if max < min or NaN). + let r = r.clamp(0.0, (w.min(h) / 2.0).max(0.0)); if r < 0.5 { return vec![[x, y], [x + w, y], [x + w, y + h], [x, y + h]]; } diff --git a/crates/chart/src/tests.rs b/crates/chart/src/tests.rs index be73da1..6af1f46 100644 --- a/crates/chart/src/tests.rs +++ b/crates/chart/src/tests.rs @@ -420,6 +420,16 @@ fn rasterize_bar_center_has_bar_color() { assert!(rasterize(&[], 100_000, 100_000, [0; 4]).is_empty()); } +#[test] +fn rasterize_does_not_panic_on_negative_rect_extents() { + let red = [255, 0, 0, 255]; + for (w, h) in [(-10.0, 10.0), (10.0, -10.0), (-10.0, -10.0), (f32::NAN, f32::NAN)] { + let rect = Prim::Rect { x: 5.0, y: 5.0, w, h, fill: Some(red), stroke: Some((red, 2.0)), radius: 0.0 }; + let img = rasterize(&[rect], 20, 20, [0, 0, 0, 0]); + assert_eq!(img.len(), 20 * 20 * 4); + } +} + #[test] fn pie_starts_at_twelve_clockwise() { let c = chart(ChartKind::Pie);