Rework Gradient into a newtype of List<Color> with optional position and midpoint attributes (#4397)

* Rework Gradient into a newtype of List<Color> with optional position and midpoint attributes

* Fix Vello stopless-gradient fallback coverage, empty legacy gradient tables, the node docs gradient swatch, NaN position elision, and wired setter input overwrites
This commit is contained in:
Keavon Chambers
2026-08-03 04:05:02 -07:00
committed by Dennis Kobert
parent 8504564f5d
commit f6b4ce71e6
36 changed files with 1112 additions and 464 deletions

View File

@@ -15,7 +15,7 @@ use graphic_types::markers::{EditorMergedLayers, Fill, Stroke as StrokeAttr};
use graphic_types::{ATTR_FILL, ATTR_STROKE, Vector};
use raster_types::{CPU, GPU, Raster};
use vector_types::gradient::{GradientSpreadMethod, GradientType as GradientTypeValue};
use vector_types::{Gradient, GradientStop, ReferencePoint};
use vector_types::{Gradient, ReferencePoint};
fn arena_exhausted() -> Interrupt {
GraphError {
@@ -555,21 +555,10 @@ pub fn flatten_gradient<'e>(
flatten_leaf_lane(content, ctx.index() as usize)
}
/// A gradient with `colors` as evenly spaced stops from 0 to 1; none makes a
/// black gradient and one repeats at both ends.
fn evenly_spaced_gradient(colors: &[Color]) -> Gradient {
let stop = |position: f64, color: Color| GradientStop { position, midpoint: 0.5, color };
match colors {
[] => Gradient::new(vec![stop(0., Color::BLACK), stop(1., Color::BLACK)]),
[color] => Gradient::new(vec![stop(0., *color), stop(1., *color)]),
colors => Gradient::new(colors.iter().enumerate().map(|(index, color)| stop(index as f64 / (colors.len() - 1) as f64, *color))),
}
}
/// Constructs a gradient from a `Color[]`, where the colors are evenly distributed as gradient stops across the range from 0 to 1.
#[node_macro::node(category("Color"), name("Colors to Gradient"))]
pub fn colors_to_gradient(_: impl Ctx, colors: IList<Color>) -> Gradient {
evenly_spaced_gradient(&colors.iter().collect::<Vec<_>>())
Gradient::from(colors.iter().collect::<Vec<_>>())
}
/// The gradient over a graphic level's color leaves, as [`colors_to_gradient`].
@@ -583,7 +572,7 @@ pub fn colors_to_gradient_graphic(_: impl Ctx, colors: IList<Graphic<'static>>)
RowStep::Continue
});
}
evenly_spaced_gradient(&leaves)
Gradient::from(leaves)
}
pub use _colors_to_gradient_graphic_mod::colors_to_gradient_graphic_entries;

View File

@@ -796,11 +796,12 @@ mod tests {
assert_eq!(three.iter().map(|stop| stop.position).collect::<Vec<_>>(), vec![0., 0.5, 1.]);
assert_eq!(three.iter().map(|stop| stop.color).collect::<Vec<_>>(), vec![Color::BLACK, Color::WHITE, Color::BLACK]);
// A lone color is a one-stop gradient and no colors a stopless one; neither is padded
let single = stops_of(vec![Color::WHITE]);
assert_eq!(single.iter().map(|stop| (stop.position, stop.color)).collect::<Vec<_>>(), vec![(0., Color::WHITE), (1., Color::WHITE)]);
assert_eq!(single.iter().map(|stop| (stop.position, stop.color)).collect::<Vec<_>>(), vec![(0., Color::WHITE)]);
let empty = stops_of(Vec::new());
assert_eq!(empty.iter().map(|stop| (stop.position, stop.color)).collect::<Vec<_>>(), vec![(0., Color::BLACK), (1., Color::BLACK)]);
assert!(empty.iter().next().is_none());
}
#[test]