New nodes: 'Gradient Type' and 'Spread Method', and add Gradient tool support for controlling these nodes (#4084)

* Use 'Transform', 'Gradient Type', and 'Spread Method' nodes for table gradients

* Add gradient widget to the tool's control bar and update where the two swap buttons go

* Fix gradient rendering

* Format

* Code review
This commit is contained in:
Keavon Chambers
2026-04-29 19:27:44 -07:00
committed by GitHub
parent e686ee9f42
commit 4b2430290c
13 changed files with 584 additions and 224 deletions

View File

@@ -1705,9 +1705,11 @@ impl Render for Table<Color> {
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
for (color, alpha_blending) in self.iter_element_values().zip(self.iter_attribute_values_or_default::<AlphaBlending>(ATTR_ALPHA_BLENDING)) {
render.leaf_tag("polyline", |attributes| {
// Chrome doesn't like drawing centered rectangles bigger than ~20 million so we draw a polyline quad instead
let max = u64::MAX;
attributes.push("points", format!("{max},{max} -{max},{max} -{max},-{max} {max},-{max}"));
// Stand-in for an infinite background. Chrome's SVG renderer keeps internal coordinates in f32 and loses
// precision past ~2^24 (~16.7 million), causing tile-boundary artifacts that pop in and out during panning.
// 1e7 stays under that limit while still being far larger than any practical document extent.
const MAX: f64 = 1e7;
attributes.push("points", format!("{MAX},{MAX} -{MAX},{MAX} -{MAX},-{MAX} {MAX},-{MAX}"));
attributes.push("fill", format!("#{}", color.to_rgb_hex_srgb_from_gamma()));
if color.a() < 1. {
@@ -1779,9 +1781,11 @@ impl Render for Table<GradientStops> {
attributes.push("width", size.x.to_string());
attributes.push("height", size.y.to_string());
} else {
// Chrome doesn't like drawing centered rectangles bigger than ~20 million so we draw a polyline quad instead
let max = u64::MAX;
attributes.push("points", format!("{max},{max} -{max},{max} -{max},-{max} {max},-{max}"));
// Stand-in for an infinite background. Chrome's SVG renderer keeps internal coordinates in f32 and loses
// precision past ~2^24 (~16.7 million), causing tile-boundary artifacts that pop in and out during panning.
// 1e7 stays under that limit while still being far larger than any practical document extent.
const MAX: f64 = 1e7;
attributes.push("points", format!("{MAX},{MAX} -{MAX},{MAX} -{MAX},-{MAX} {MAX},-{MAX}"));
}
let mut stop_string = String::new();

View File

@@ -2,10 +2,6 @@ use core_types::{Color, render_complexity::RenderComplexity};
use dyn_any::DynAny;
use glam::{DAffine2, DVec2};
/// Default scale applied to a freshly-created `Table<GradientStops>` item's transform.
/// Places the unit gradient line (the +X unit vector in local space) inside a 100×100 document-space box.
pub const GRADIENT_TABLE_DEFAULT_SCALE: f64 = 100.;
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, Hash, graphene_hash::CacheHash, DynAny, node_macro::ChoiceType)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]

View File

@@ -8,7 +8,7 @@ pub mod vector;
// Re-export commonly used types at the crate root
pub use core_types as gcore;
pub use gradient::{GradientStop, GradientStops, GradientType};
pub use gradient::{GradientSpreadMethod, GradientStop, GradientStops, GradientType};
pub use math::{QuadExt, RectExt};
pub use subpath::Subpath;
pub use vector::Vector;