Merge pull request #2397 from marcoarnulfo/fix/freeform-gradient-color-effects

Color effects recolour the points of a freeform gradient
This commit is contained in:
BFlat
2026-10-17 15:11:45 +07:00
committed by GitHub
2 changed files with 25 additions and 2 deletions
+9 -2
View File
@@ -387,7 +387,9 @@ impl Paint {
}
/// Apply `f` to the colours of this paint that can link to a swatch (a solid colour, each
/// gradient stop) with their link and tint; `f` returns true when it changed them. A colour
/// left without a link gets tint 1. Returns whether anything changed.
/// left without a link gets tint 1. A freeform gradient's points, which it draws from, go
/// through `f` too, as unlinked colours (a link `f` gives them is dropped). Returns whether
/// anything changed.
pub fn map_links(&mut self, f: &mut dyn FnMut(&mut Color, &mut Option<String>, &mut f32) -> bool) -> bool {
let mut one = |c: &mut Color, link: &mut Option<String>, tint: &mut f32| {
let changed = f(c, link, tint);
@@ -398,7 +400,12 @@ impl Paint {
};
match self {
Paint::Solid { color, swatch, tint } => one(color, swatch, tint),
Paint::Gradient(g) => g.gradient.stops.iter_mut().fold(false, |ch, s| one(&mut s.color, &mut s.swatch, &mut s.tint) | ch),
Paint::Gradient(g) => {
let stops = g.gradient.stops.iter_mut().fold(false, |ch, s| one(&mut s.color, &mut s.swatch, &mut s.tint) | ch);
let points =
g.freeform.iter_mut().flat_map(|ff| ff.points.iter_mut()).fold(false, |ch, p| one(&mut p.color, &mut None, &mut 1.0) | ch);
stops | points
}
_ => false,
}
}
+16
View File
@@ -490,4 +490,20 @@ mod tests {
assert_eq!(out.appearance.items[0].paint(), p.appearance.items[0].paint());
assert!(out.appearance.items[1].effects().is_empty());
}
#[test]
fn adjust_recolours_the_points_of_a_freeform_gradient() {
use vectorcraft_doc::color::{Freeform, FreeformPoint, Gradient, GradientKind, GradientPaint};
let mut gp = GradientPaint::new(Gradient { kind: GradientKind::Freeform, ..Gradient::default() });
let pt = |x, c| FreeformPoint::new(kurbo::Point::new(x, 5.0), c);
gp.set_freeform(Freeform { points: vec![pt(2.0, Color::rgb(1.0, 0.0, 0.0)), pt(8.0, Color::rgb(0.0, 0.0, 1.0))], ..Default::default() });
let fill = Appearance::basic(Paint::Gradient(Box::new(gp)), Paint::None, 0.0);
let mut p = Node::path(NodeId(1), shapes::rectangle(Rect::new(0.0, 0.0, 10.0, 10.0)), fill);
p.appearance.effects.push(Effect { id: "adjust.hueSaturation".into(), params: json!({"hue": 120}), visible: true });
let out = adjust(&p, None, &mut |_, _| None).unwrap();
let Paint::Gradient(g) = out.appearance.fill_paint() else { panic!("a gradient fill") };
// The points are what a freeform gradient draws from, not its stops.
let hexes: Vec<String> = g.freeform.as_ref().unwrap().points.iter().map(|p| p.color.to_hex()).collect();
assert_eq!(hexes, ["#00ff00", "#ff0000"]);
}
}