From b71d5ebdfb3bc44121d292fbdd23fddfd098aaa8 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Tue, 10 Nov 2026 15:59:25 -0800 Subject: [PATCH] Symbols: separations, proofing and color conversion reach a dynamic instance's own colors visit_node_colors visits the fill and stroke paints a dynamic symbol instance keeps for objects of its art (symbol_overrides). Before, print separations, Separations Preview and document color conversion left those colors as they were, so an instance's own fill printed and previewed unseparated. --- crates/doc/src/inks.rs | 46 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/crates/doc/src/inks.rs b/crates/doc/src/inks.rs index 696b27413..e10c424ee 100644 --- a/crates/doc/src/inks.rs +++ b/crates/doc/src/inks.rs @@ -110,8 +110,9 @@ fn visit_paint(p: &mut Paint, f: &mut ColorVisitor) { } /// Visit every colour of a node tree (fills, strokes, gradient stops, text runs, mesh points, an -/// image's colorize color, not opacity masks) with its swatch link and tint. Mesh points have no -/// link: changes to it are dropped. +/// image's colorize color, the fills and strokes a dynamic symbol instance keeps for objects of its +/// art, not opacity masks) with its swatch link and tint. Mesh points have no link: changes to it +/// are dropped. pub fn visit_node_colors(n: &mut Node, f: &mut ColorVisitor) { for it in &mut n.appearance.items { match it { @@ -119,8 +120,13 @@ pub fn visit_node_colors(n: &mut Node, f: &mut ColorVisitor) { AppearanceItem::Stroke(l) => visit_paint(&mut l.paint, f), } } - if let Some(p) = n.extras.0.as_deref_mut().and_then(|e| e.colorize.as_deref_mut()) { - visit_paint(p, f); + if let Some(e) = n.extras.0.as_deref_mut() { + if let Some(p) = e.colorize.as_deref_mut() { + visit_paint(p, f); + } + for p in e.symbol_overrides.iter_mut().flat_map(|o| [&mut o.fill, &mut o.stroke]).flatten() { + visit_paint(p, f); + } } match &mut n.kind { NodeKind::Text(t) => { @@ -144,7 +150,8 @@ pub fn visit_node_colors(n: &mut Node, f: &mut ColorVisitor) { } /// Apply `f` to every colour of a node tree (fills, strokes, gradient stops, text runs, mesh -/// points) given its swatch link and tint, keeping the links. +/// points, a dynamic symbol instance's own fills and strokes) given its swatch link and tint, +/// keeping the links. pub fn map_node_colors(n: &mut Node, f: &mut dyn FnMut(&Color, Link) -> Color) { visit_node_colors(n, &mut |c, swatch, tint| *c = f(c, swatch.as_deref().map(|s| (s, *tint)))); } @@ -158,3 +165,32 @@ pub fn map_document_colors(doc: &mut Document, f: &mut dyn FnMut(&Color, Link) - map_node_colors(Arc::make_mut(&mut s.art), f); } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{NodeId, SymbolOverride}; + use vectorcraft_geom::Affine; + + #[test] + fn a_dynamic_instances_own_fills_and_strokes_are_visited() { + let red = Color::rgb(1.0, 0.0, 0.0); + let blue = Color::rgb(0.0, 0.0, 1.0); + let spot = Paint::Solid { color: red, swatch: Some("Spot".into()), tint: 0.5 }; + let mut inst = Node::new(NodeId(1), NodeKind::SymbolInstance { symbol: "S".into(), xf: Affine::IDENTITY }); + inst.extras_mut().symbol_overrides = vec![ + SymbolOverride { path: vec![0], fill: Some(spot), stroke: Some(Paint::solid(red)), ..Default::default() }, + SymbolOverride { path: vec![1], opacity: Some(0.5), ..Default::default() }, + ]; + let mut links = vec![]; + map_node_colors(&mut inst, &mut |_, link| { + links.push(link.map(|(s, t)| (s.to_string(), t))); + blue + }); + assert_eq!(links, vec![Some(("Spot".to_string(), 0.5)), None], "each override paint is visited once, with its link"); + let o = &inst.extras().symbol_overrides; + assert_eq!(o[0].fill, Some(Paint::Solid { color: blue, swatch: Some("Spot".into()), tint: 0.5 }), "the link is kept"); + assert_eq!(o[0].stroke, Some(Paint::solid(blue))); + assert_eq!((o[1].fill.as_ref(), o[1].stroke.as_ref()), (None, None), "an override without paint gets none"); + } +}