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 GitHub
parent e52a442504
commit 2f24459344
34 changed files with 1121 additions and 475 deletions

View File

@@ -6,7 +6,7 @@ use std::sync::atomic::AtomicU64;
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::token::Comma;
use syn::{Error, Ident, PatIdent, Token, WhereClause, WherePredicate, parse_quote};
use syn::{Error, Expr, ExprPath, Ident, PatIdent, Token, WhereClause, WherePredicate, parse_quote};
static NODE_ID: AtomicU64 = AtomicU64::new(0);
pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn) -> syn::Result<TokenStream2> {
@@ -191,6 +191,20 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
})
.collect();
let default_colors: Vec<_> = regular_fields
.iter()
.map(|field| match field.ty.regular() {
Some(RegularParsedField {
value_source: ParsedValueSource::Default(data),
..
}) => match color_constant_paths(data) {
Some(paths) => quote!(Some(&[#(#paths),*])),
None => quote!(None),
},
_ => quote!(None),
})
.collect();
let default_types: Vec<_> = regular_fields
.iter()
.enumerate()
@@ -858,6 +872,7 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
hidden: #input_hidden,
exposed: #exposed,
value_source: #value_sources,
default_colors: #default_colors,
default_type: #default_types,
number_soft_min: #number_soft_min_values,
number_soft_max: #number_soft_max_values,
@@ -881,6 +896,26 @@ pub(crate) fn generate_node_code(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
})
}
/// The `Color::*` constant paths making up a default expression, when it consists solely of them (the form used by color and gradient parameter defaults).
fn color_constant_paths(tokens: &TokenStream2) -> Option<Vec<ExprPath>> {
use syn::parse::Parser;
let expressions = Punctuated::<Expr, Token![,]>::parse_terminated.parse2(tokens.clone()).ok()?;
if expressions.is_empty() {
return None;
}
expressions
.into_iter()
.map(|expression| {
let Expr::Path(path) = expression else { return None };
let segments = &path.path.segments;
let is_color_constant = path.qself.is_none() && segments.len() == 2 && segments[0].ident == "Color" && segments.iter().all(|segment| segment.arguments.is_none());
is_color_constant.then_some(path)
})
.collect()
}
/// Generates the per-parameter symbol types used to reference this node's inputs.
fn generate_node_input_references(parsed: &ParsedNodeFn, field_idents: &[&PatIdent], core_types: &TokenStream2, identifier: &Ident, cfg: &TokenStream2) -> TokenStream2 {
let inputs_module_name = format_ident!("{}", parsed.struct_name.to_string().to_case(Case::Snake));