security(pathops): signed zeros, reported budget rejections, and a fill-only fallback

Boxes that touch at -0.0/+0.0 now count as overlapping, so the pair cap cannot be skipped. try_boolean_n, try_unite_all and try_area report a refused input, and the Pathfinder shape-mode unite and the Blob Brush use them to show an error. When the planar map is over its budget, the fallback leaves out paths that fill nothing so a flood of cutting lines cannot take the filled shapes down with it.
This commit is contained in:
Dylan M. Taylor
2026-10-25 16:04:29 -04:00
parent cd80d1d859
commit 0eebd533c5
6 changed files with 76 additions and 7 deletions
+1 -1
View File
@@ -1515,7 +1515,7 @@ fn blob(s: &mut Session, p: &Value) -> Result<Value> {
}
let mut inputs: Vec<(&PathData, FillRule)> = vec![(&region, FillRule::NonZero)];
inputs.extend(merge_ids.iter().map(|(_, pd, r)| (pd, *r)));
let merged = po::unite_all(&inputs);
let merged = po::try_unite_all(&inputs).map_err(|e| EngineError::Other(e.to_string()))?;
let Some(((keep, _, _), rest)) = merge_ids.split_last() else {
return insert_look(s, "Blob Brush", path_kind(region), ap, None, keep_selected);
};
+1 -1
View File
@@ -452,7 +452,7 @@ fn run_pf(s: &mut Session, op: PathfinderOp) -> Result<Value> {
let parts: Vec<(PathData, FillRule)> = lv.iter().filter_map(node_path).collect();
let refs: Vec<(&PathData, FillRule)> = parts.iter().map(|(p, r)| (p, *r)).collect();
let name = n.name.clone().or_else(|| lv.iter().find_map(|l| l.name.clone()));
push(po::unite_all(&refs), FillRule::NonZero, style_of(top), name);
push(po::try_unite_all(&refs).map_err(|e| EngineError::Other(e.to_string()))?, FillRule::NonZero, style_of(top), name);
} else {
for l in &lv {
if let Some((p, r)) = node_path(l) {