fix(pathops): sanitize a brush's width profile once before sampling (#1948)

This commit is contained in:
Dylan M. Taylor authored and GitHub committed 2026-11-03 14:40:54 -05:00
1 parent 35684eaa02
commit 53ebf1f39c
2 files changed
+14 -1

No files matched your search

+3 -1
View File
@@ -131,7 +131,9 @@ pub fn outline(path: &BezPath, width: f64, props: &StrokeProps, brush: &Brush) -
let p = preset(&brush.preset)?;
let unit = shape(p.id)?;
let lines = polylines(path)?;
let scale = |t: f64| width * props.profile().map_or(1.0, |pr| pr.scale_at(t));
// Sanitized once: at most 64 points, so each sample's symmetry scan stays cheap.
let profile = props.profile().map(|pr| pr.sanitized());
let scale = |t: f64| width * profile.as_ref().map_or(1.0, |pr| pr.scale_at(t));
let mut out = BezPath::new();
match p.kind {
BrushKind::Stretch => {
+11
View File
@@ -72,3 +72,14 @@ fn a_width_profile_scales_the_brush() {
let (first, last) = (parts.first().unwrap().bounding_box(), parts.last().unwrap().bounding_box());
assert!(last.width() > first.width() * 3.0, "{first:?} {last:?}");
}
#[test]
fn an_unsanitized_profile_is_bounded_before_sampling() {
// 100k points, all past the 64-point cap and out of range: the brush reads the clamped profile.
let raw = WidthProfile { points: (0..100_000).map(|i| figcraft_doc::WidthPoint::new(f64::from(i), 1e300)).collect() };
let b = brush("taper");
let mut p = props(1.0, &b);
p.width_profile = Some(raw);
let out = outline(&line(50.0), 1.0, &p, &b).unwrap();
assert!(out.bounding_box().height() <= 2.0 * WidthProfile::MAX_SCALE);
}