fix: Pathfinder results keep the source's name and SVG id (#1293)

This commit is contained in:
Ikki Nishihara
2026-10-12 15:17:01 +07:00
committed by bflatastic
parent 18e538ec94
commit c85570c8b2
6 changed files with 183 additions and 12 deletions
+15 -5
View File
@@ -310,10 +310,11 @@ fn run_pf(s: &mut Session, op: PathfinderOp) -> Result<Value> {
matches!(op, PathfinderOp::Unite | PathfinderOp::MinusFront | PathfinderOp::Intersect | PathfinderOp::Exclude | PathfinderOp::MinusBack);
let label = pf_label(op);
let ids = s.edit(label, |d, sel| {
// Build the stack (back → front) with a style per entry.
// Build the stack (back → front); names are separate from paint/style identity.
let mut styles: Vec<Style> = vec![];
let mut shapes: Vec<po::Shape> = vec![];
let mut push = |mut path: PathData, rule: FillRule, st: Style| {
let mut names: Vec<Option<String>> = vec![];
let mut push = |mut path: PathData, rule: FillRule, st: Style, name: Option<String>| {
if path.is_empty() {
return;
}
@@ -332,6 +333,7 @@ fn run_pf(s: &mut Session, op: PathfinderOp) -> Result<Value> {
}
};
shapes.push(po::Shape::new(path, rule, key as u64));
names.push(name);
};
for id in &roots {
let n = d.node(*id).ok_or(EngineError::NoNode(*id))?;
@@ -347,11 +349,12 @@ fn run_pf(s: &mut Session, op: PathfinderOp) -> Result<Value> {
// A group acts as one shape (the union of its leaves) with its top leaf's style.
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();
push(po::unite_all(&refs), FillRule::NonZero, style_of(top));
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);
} else {
for l in &lv {
if let Some((p, r)) = node_path(l) {
push(p, r, style_of(l));
push(p, r, style_of(l), n.name.clone().or_else(|| l.name.clone()));
}
}
}
@@ -371,7 +374,14 @@ fn run_pf(s: &mut Session, op: PathfinderOp) -> Result<Value> {
let r =
results.into_iter().find(|r| !r.path.is_empty()).ok_or_else(|| EngineError::Other(format!("{label} produced an empty result")))?;
let style = styles.get(r.key as usize).ok_or_else(|| EngineError::Other(format!("{label}: lost track of a shape's style")))?;
shape_node_styled(d, r.path, style)
let mut n = shape_node_styled(d, r.path, style);
n.name = match op {
// A subtraction keeps its surviving source's identity, even when unnamed.
PathfinderOp::MinusFront => names.first().cloned().flatten(),
PathfinderOp::MinusBack => names.last().cloned().flatten(),
_ => names.into_iter().flatten().next(),
};
n
} else {
let mut children = vec![];
for r in results {