Merge upstream/main into rfx-masks-shapes

render: upstream moved the tests_*.rs modules into crates/render/src/tests/; the branch's
tests_mask_feather.rs now lives at tests/mask_feather.rs and is registered in tests.rs.
path: rect() keeps the branch's explicit-outline version with an added NaN guard on the
roundness clamp bound (main's fix for the same panic).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
vangel76
2026-10-27 16:57:13 +01:00
co-authored by Claude Sonnet 5.5
812 changed files with 67230 additions and 44816 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
//! MIT OR Apache-2.0), reworked to take and return kurbo paths directly.
//!
//! Inputs are closed implicitly (a filled open path is painted as if closed). The sweep splits
//! curves at intersections and y-extrema; [`tidy_segments`] re-joins pieces that came from one
//! curves at intersections and y-extrema; `tidy_segments` re-joins pieces that came from one
//! input curve (exactly) or one smooth run (by least-squares refit), so results carry roughly as
//! few vertices as the inputs. Output contours are simple and consistently oriented (holes wind
//! opposite to their outer contour), so they fill the same under either fill rule.
+8 -1
View File
@@ -137,7 +137,9 @@ pub fn from_kurbo(path: &BezPath) -> Vec<ShapePath> {
pub fn rect(size: [f64; 2], pos: [f64; 2], roundness: f64) -> BezPath {
let (w, h) = (size[0].abs(), size[1].abs());
let (x0, y0, x1, y1) = (pos[0] - w / 2.0, pos[1] - h / 2.0, pos[0] + w / 2.0, pos[1] + h / 2.0);
let rad = if roundness.is_finite() { roundness.clamp(0.0, w.min(h) / 2.0) } else { 0.0 };
let max_rad = w.min(h) / 2.0;
// `f64::clamp` panics on a NaN bound (both size components NaN): fall back to no roundness.
let rad = if roundness.is_finite() && !max_rad.is_nan() { roundness.clamp(0.0, max_rad) } else { 0.0 };
let mut p = BezPath::new();
if rad <= 0.0 {
p.move_to((x1, y0));
@@ -410,6 +412,11 @@ mod tests {
assert!(near(a, (80.0, 150.0)) && near(b, (-200.0, -130.0)), "{a:?} {b:?}");
}
#[test]
fn rect_with_nan_size_does_not_panic() {
let _ = rect([f64::NAN, f64::NAN], [0.0, 0.0], 5.0);
}
#[test]
fn roundtrip_vertex_model() {
let sp = ShapePath::ellipse([10.0, 20.0], 40.0, 30.0);
+1 -1
View File
@@ -6,7 +6,7 @@
//! with "outside" so every contour closes.
//! 2. **Douglas–Peucker** simplification of each closed loop to the Tolerance (pixels).
//! 3. **Bezier fitting**: each simplified span is fitted with one cubic (least squares with fixed
//! end tangents, Newton reparameterisation; [`crate::fit`]). The tangent at each vertex is the
//! end tangents, Newton reparameterisation; `crate::fit`). The tangent at each vertex is the
//! chord direction at Corner Roundness 0 (straight segments, sharp corners) and the smooth
//! (Catmull–Rom) direction at 100 %, blended between.
//!