Bring the editor onto the reconciled node catalog and paint carrier

This commit is contained in:
Dennis Kobert
2026-09-08 16:33:52 +00:00
parent 3830ace926
commit 33b20d6329
11 changed files with 74 additions and 80 deletions

View File

@@ -2767,7 +2767,7 @@ impl DocumentMessageHandler {
}
let solidify_stroke_definition = document_node_definitions::resolve_proto_node_type(graphene_std::vector::solidify_stroke::IDENTIFIER).expect("Solidify Stroke node should exist");
let item_at_index_definition = document_node_definitions::resolve_proto_node_type(graphene_std::graphic::item_at_index::IDENTIFIER).expect("Item at Index node should exist");
let item_at_index_definition = document_node_definitions::resolve_proto_node_type(graphene_std::graphic::index_elements::IDENTIFIER).expect("Item at Index node should exist");
let mut resulting_layers: Vec<NodeId> = Vec::new();
@@ -2777,13 +2777,14 @@ impl DocumentMessageHandler {
continue;
}
let appearance = self.network_interface.document_metadata().layer_appearance_attributes.get(&layer);
let metadata = self.network_interface.document_metadata();
let fill_paint = metadata.layer_fill_attributes.get(&layer);
let stroke_paint = metadata.layer_stroke_attributes.get(&layer);
let has_fill = appearance.is_some_and(|appearance| appearance.has_painted_cover(Cover::Fill));
let has_fill = fill_paint.is_some_and(|paint| paint.element(0).is_some_and(|graphic| !graphic.is_guaranteed_fully_transparent()));
// A visible stroke needs both renderable geometry (non-zero weight) and paint that draws something
let has_stroke = appearance.is_some_and(|appearance| {
appearance.first_coverage_of(Cover::Stroke).is_some_and(|coverage| coverage.stroke_params().has_renderable_stroke())
&& appearance.first_paint_of(Cover::Stroke).is_some_and(|paint| !paint.is_guaranteed_fully_transparent())
let has_stroke = stroke_paint.is_some_and(|paint| {
graphene_std::renderer::stroke_params(paint).has_renderable_stroke() && paint.element(0).is_some_and(|graphic| !graphic.is_guaranteed_fully_transparent())
});
// No stroke means there's nothing to solidify. Fill-only layers are already in the desired form, so skip.

View File

@@ -12,7 +12,7 @@ use glam::{DAffine2, DVec2, IVec2};
use graph_craft::application_io::resource::ResourceId;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{NodeId, NodeInput};
use graph_craft::{ProtoNodeIdentifier, concrete};
use graph_craft::{ProtoNodeIdentifier, concrete, descriptor};
use graphene_std::list::List;
use graphene_std::raster::BlendMode;
use graphene_std::raster_types::Image;
@@ -71,8 +71,8 @@ impl<'a> ModifyInputsContext<'a> {
/// Creates an artboard as the primary export for the document network.
pub fn create_artboard(&mut self, new_id: NodeId, location: DVec2, dimensions: DVec2, background: Color, clip: bool) -> LayerNodeIdentifier {
let artboard_node_template = resolve_network_node_type("Artboard").expect("Node").node_template_input_override([
Some(NodeInput::type_default(concrete!(List<Artboard>), true)),
Some(NodeInput::type_default(concrete!(List<Graphic>), true)),
Some(NodeInput::type_default(descriptor!(List<Artboard>), true)),
Some(NodeInput::type_default(descriptor!(List<Graphic>), true)),
Some(NodeInput::value(TaggedValue::DVec2(location), false)),
Some(NodeInput::value(TaggedValue::DVec2(dimensions), false)),
Some(NodeInput::value(TaggedValue::Color(background), false)),
@@ -86,7 +86,7 @@ impl<'a> ModifyInputsContext<'a> {
let boolean = resolve_proto_node_type(graphene_std::path_bool_nodes::boolean_operation::IDENTIFIER)
.expect("Boolean node does not exist")
.node_template_input_override([
Some(NodeInput::type_default(concrete!(List<Graphic>), true)),
Some(NodeInput::type_default(descriptor!(List<Graphic>), true)),
Some(NodeInput::value(TaggedValue::BooleanOperation(operation), false)),
]);
@@ -98,7 +98,7 @@ impl<'a> ModifyInputsContext<'a> {
pub fn insert_blend_data(&mut self, layer: LayerNodeIdentifier, count: f64) -> NodeId {
let blend = resolve_network_node_type("Blend")
.expect("Blend node does not exist")
.node_template_input_override([Some(NodeInput::type_default(concrete!(List<Graphic>), true)), Some(NodeInput::value(TaggedValue::F64(count), false))]);
.node_template_input_override([Some(NodeInput::type_default(descriptor!(List<Graphic>), true)), Some(NodeInput::value(TaggedValue::F64(count), false))]);
let blend_id = NodeId::new();
self.network_interface.insert_node(blend_id, blend, &[]);
@@ -110,7 +110,7 @@ impl<'a> ModifyInputsContext<'a> {
pub fn insert_morph_data(&mut self, layer: LayerNodeIdentifier) -> NodeId {
let morph = resolve_proto_node_type(graphene_std::vector::morph::IDENTIFIER)
.expect("Morph node does not exist")
.node_template_input_override([Some(NodeInput::type_default(concrete!(List<Graphic>), true)), Some(NodeInput::value(TaggedValue::F64(0.5), false))]);
.node_template_input_override([Some(NodeInput::type_default(descriptor!(List<Graphic>), true)), Some(NodeInput::value(TaggedValue::F64(0.5), false))]);
let morph_id = NodeId::new();
self.network_interface.insert_node(morph_id, morph, &[]);
@@ -859,9 +859,9 @@ impl<'a> ModifyInputsContext<'a> {
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::StrokeJoin(stroke.join), false), true);
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::MiterLimitInput);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(stroke.join_miter_limit), false), false);
// Our stroke node keeps a paint order input rather than encoding the order by Fill/Stroke node adjacency
// Our stroke node keeps a paint order input rather than encoding the order by Fill/Stroke node adjacency, and master's `Stroke` no longer carries one to copy
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::PaintOrderInput);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::PaintOrder(stroke.paint_order), false), false);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::PaintOrder(Default::default()), false), false);
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::DashPatternInput);
self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::DashPattern(stroke.dash_lengths), false), true);
let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::DashOffsetInput);

View File

@@ -14,6 +14,7 @@ use graph_craft::ProtoNodeIdentifier;
use graph_craft::document::value::*;
use graph_craft::document::*;
use graph_craft::concrete;
use graph_craft::descriptor;
use graphene_std::extract_xy::XY;
use graphene_std::list::List;
use graphene_std::raster::{CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, NoiseType, RedGreenBlueAlpha};
@@ -162,7 +163,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
// Collection of the content into the layer's group; the wrap keeps the content level's element type for the legacy boundary
NodeTemplate {
inputs: vec![NodeInput::import(generic!(T), 1)],
implementation: NodeTemplateImplementation::ProtoNode(graphic::wrap_graphic::IDENTIFIER),
implementation: NodeTemplateImplementation::ProtoNode(graphic::into_group::IDENTIFIER),
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-21, -1)),
..Default::default()
},
@@ -203,7 +204,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
.collect(),
..Default::default()
}),
inputs: vec![NodeInput::type_default(concrete!(List<Graphic>), true), NodeInput::type_default(concrete!(List<Graphic>), true)],
inputs: vec![NodeInput::type_default(descriptor!(List<Graphic>), true), NodeInput::type_default(descriptor!(List<Graphic>), true)],
input_metadata: vec![("Base", "TODO").into(), ("Content", "TODO").into()],
output_names: vec!["Out".to_string()],
node_type_metadata: NodeTypePersistentMetadata::layer(IVec2::new(0, 0)),
@@ -297,8 +298,8 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
..Default::default()
}),
inputs: vec![
NodeInput::type_default(concrete!(List<Artboard>), true),
NodeInput::type_default(concrete!(List<Graphic>), true),
NodeInput::type_default(descriptor!(List<Artboard>), true),
NodeInput::type_default(descriptor!(List<Graphic>), true),
NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false),
NodeInput::value(TaggedValue::DVec2(DVec2::new(1920., 1080.)), false),
NodeInput::value(TaggedValue::Color(Color::WHITE), false),
@@ -493,11 +494,11 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
..Default::default()
}),
inputs: vec![
NodeInput::type_default(concrete!(List<Vector>), true),
NodeInput::type_default(descriptor!(List<Vector>), true),
NodeInput::value(TaggedValue::F64(10.), false),
NodeInput::value(TaggedValue::Bool(Default::default()), false),
NodeInput::value(TaggedValue::InterpolationDistribution(Default::default()), false),
NodeInput::type_default(concrete!(List<Vector>), false),
NodeInput::type_default(descriptor!(List<Vector>), false),
],
input_metadata: vec![
("Content", "TODO").into(),
@@ -583,7 +584,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
.collect(),
..Default::default()
}),
inputs: vec![NodeInput::type_default(concrete!(List<Vector>), true)],
inputs: vec![NodeInput::type_default(descriptor!(List<Vector>), true)],
input_metadata: vec![("Vector", "TODO").into()],
output_names: vec!["Vector".to_string()],
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
@@ -673,7 +674,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
..Default::default()
}),
inputs: vec![
NodeInput::type_default(concrete!(List<Vector>), true),
NodeInput::type_default(descriptor!(List<Vector>), true),
NodeInput::value(
TaggedValue::Footprint(Footprint {
transform: DAffine2::from_scale_angle_translation(DVec2::new(1000., 1000.), 0., DVec2::new(0., 0.)),
@@ -750,7 +751,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
.collect(),
..Default::default()
}),
inputs: vec![NodeInput::type_default(concrete!(List<Raster<CPU>>), true)],
inputs: vec![NodeInput::type_default(descriptor!(List<Raster<CPU>>), true)],
input_metadata: vec![("Image", "TODO").into()],
output_names: vec!["".to_string(), "Red".to_string(), "Green".to_string(), "Blue".to_string(), "Alpha".to_string()],
..Default::default()
@@ -803,7 +804,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
category: "",
node_template: NodeTemplate {
implementation: NodeTemplateImplementation::Extract,
inputs: vec![NodeInput::type_default(concrete!(DocumentNode), true)],
inputs: vec![NodeInput::type_default(descriptor!(DocumentNode), true)],
input_metadata: vec![("Node", "TODO").into()],
output_names: vec!["Document Node".to_string()],
..Default::default()
@@ -917,7 +918,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
..Default::default()
}),
inputs: vec![
NodeInput::type_default(concrete!(Vector), true),
NodeInput::type_default(descriptor!(Vector), true),
NodeInput::value(TaggedValue::VectorModification(Default::default()), false),
],
input_metadata: vec![("Content", "TODO").into(), ("Modification", "TODO").into()],
@@ -1585,7 +1586,7 @@ impl InputTypeConstraint {
// Find the union of all the possible types from the dynamic executor implementations
let mut result_accepted = Self::empty();
for node_io in implementations.keys() {
for node_io in implementations.iter().map(|entry| &entry.io) {
if let Some(input_type) = node_io.inputs.get(input_index) {
result_accepted.insert(input_type);
}

View File

@@ -27,7 +27,7 @@ impl FrontendGraphDataType {
match TaggedValue::from_type_or_none(input) {
TaggedValue::U32(_) | TaggedValue::U64(_) | TaggedValue::F32(_) | TaggedValue::F64(_) | TaggedValue::DVec2(_) | TaggedValue::F64Array(_) | TaggedValue::DAffine2(_) => Self::Number,
TaggedValue::Color(_) => Self::Color,
TaggedValue::LegacyGradient(_) | TaggedValue::Gradient(_) => Self::Gradient,
TaggedValue::LegacyGradient(_) | TaggedValue::GradientRamp(_) => Self::Gradient,
TaggedValue::String(_) => Self::Typography,
// Types whose `TaggedValue` variant has been removed are routed through `TypeDefault` and identified by the descriptor's type name.
TaggedValue::TypeDefault(td) => match td.name.as_ref() {

View File

@@ -236,11 +236,8 @@ impl DocumentMetadata {
/// bounds for non-vector layers (groups, raster, text, color, gradient).
pub fn bounding_box_document_with_stroke(&self, layer: LayerNodeIdentifier) -> Option<[DVec2; 2]> {
if let Some(vector) = self.layer_vector_data.get(&layer) {
let stroke = self
.layer_appearance_attributes
.get(&layer)
.and_then(|appearance| appearance.first_coverage_of(graphene_std::Cover::Stroke))
.map(graphene_std::Coverage::stroke_params);
// The stroke geometry rides the stroke paint list's own attribute columns, the carrier that replaced the deleted `Vector::stroke`.
let stroke = self.layer_stroke_attributes.get(&layer).map(|paint| graphene_std::renderer::stroke_params(paint));
if let Some(bounds) = vector.stroke_inclusive_bounding_box_with_transform(self.transform_to_document(layer), stroke.as_ref()) {
return Some(bounds);
}

View File

@@ -194,7 +194,7 @@ impl NodeNetworkInterface {
log::error!("Proto node {node:?} not found in the node registry, in layer_chain_hosts_node");
return false;
};
implementations.keys().any(|node_io| node_io.inputs.first().is_some_and(|content| content.nested_type() == element))
implementations.iter().map(|entry| &entry.io).any(|node_io| node_io.inputs.first().is_some_and(|content| content.nested_type() == element))
}
None => !matches!(chain_type, TypeSource::Invalid),
}

View File

@@ -9,7 +9,7 @@ use glam::{DVec2, IVec2};
use graph_craft::application_io::resource::{DataSource, Resource, ResourceHash, ResourceId};
use graph_craft::document::DocumentNode;
use graph_craft::document::{DocumentNodeImplementation, NodeInput, value::TaggedValue};
use graph_craft::{Type, concrete};
use graph_craft::{Type, concrete, descriptor};
use graphene_std::Color;
use graphene_std::ParameterRef;
use graphene_std::ProtoNodeIdentifier;
@@ -148,7 +148,7 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
aliases: &["graphene_core::graphic::FlattenVectorNode", "graphene_core::graphic_element::FlattenVectorNode"],
},
NodeReplacement {
node: graphene_std::graphic::item_at_index::IDENTIFIER,
node: graphene_std::graphic::index_elements::IDENTIFIER,
aliases: &[
"graphene_core::graphic_element::IndexNode",
"graphene_core::graphic::IndexNode",
@@ -158,15 +158,7 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
],
},
NodeReplacement {
node: graphene_std::graphic::read_attribute_gradient_form::IDENTIFIER,
aliases: &["graphic_nodes::graphic::ReadAttributeGradientTypeNode"],
},
NodeReplacement {
node: graphene_std::graphic::read_attribute_gradient_spread::IDENTIFIER,
aliases: &["graphic_nodes::graphic::ReadAttributeSpreadMethodNode"],
},
NodeReplacement {
node: graphene_std::graphic::remove_at_index::IDENTIFIER,
node: graphene_std::graphic::omit_element::IDENTIFIER,
aliases: &["graphic_nodes::graphic::OmitElementNode"],
},
NodeReplacement {
@@ -784,7 +776,7 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
aliases: &["graphene_core::vector::ClosePathNode"],
},
NodeReplacement {
node: graphene_std::vector::list_length::IDENTIFIER,
node: graphene_std::vector::count_elements::IDENTIFIER,
aliases: &["graphene_core::vector::CountElementsNode"],
},
NodeReplacement {
@@ -1425,10 +1417,10 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
if reference == DefinitionIdentifier::ProtoNode(graphene_std::vector::copy_to_points::IDENTIFIER) {
let mut node_template = node_definition.default_node_template();
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[1].clone(), network_path);
document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[0].clone(), network_path);
document.network_interface.set_input(&InputConnector::node_at_index(*node_id, 0), old_inputs[1].clone(), network_path);
document.network_interface.set_input(&InputConnector::node_at_index(*node_id, 1), old_inputs[0].clone(), network_path);
for (index, input) in old_inputs.into_iter().enumerate().skip(2) {
document.network_interface.set_input(&InputConnector::node(*node_id, index), input, network_path);
document.network_interface.set_input(&InputConnector::node_at_index(*node_id, index), input, network_path);
}
}
@@ -1436,10 +1428,10 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
if reference == DefinitionIdentifier::ProtoNode(graphene_std::repeat::repeat_on_points::IDENTIFIER) {
let mut node_template = node_definition.default_node_template();
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[1].clone(), network_path);
document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[0].clone(), network_path);
document.network_interface.set_input(&InputConnector::node_at_index(*node_id, 0), old_inputs[1].clone(), network_path);
document.network_interface.set_input(&InputConnector::node_at_index(*node_id, 1), old_inputs[0].clone(), network_path);
for (index, input) in old_inputs.into_iter().enumerate().skip(2) {
document.network_interface.set_input(&InputConnector::node(*node_id, index), input, network_path);
document.network_interface.set_input(&InputConnector::node_at_index(*node_id, index), input, network_path);
}
}
@@ -1898,7 +1890,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
// The stored no-paint sentinel was the `List<Graphic>` type default before the paint connectors ranked down to `Item<Graphic>`.
// This must run before the stale-List-default cleanup below, which would otherwise adopt the definition's default paint.
{
let legacy_no_paint = TaggedValue::TypeDefault(concrete!(List<graphene_std::Graphic>));
let legacy_no_paint = TaggedValue::TypeDefault(descriptor!(List<graphene_std::Graphic>));
let paint_parameters: &[ParameterRef] = &[graphene_std::vector::fill::PaintInput.into(), graphene_std::vector::stroke::PaintInput.into()];
for parameter in paint_parameters {
if reference != DefinitionIdentifier::ProtoNode(parameter.node_identifier.clone()) {
@@ -2490,7 +2482,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
};
// Create List Length node: counts content `List` items → N
let Some(list_length_def) = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector::list_length::IDENTIFIER)) else {
let Some(list_length_def) = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector::count_elements::IDENTIFIER)) else {
log::error!("Could not get list_length node from definition when upgrading morph");
document.network_interface.set_input(&InputConnector::node_at_index(*node_id, 1), old_inputs[1].clone(), network_path);
return None;
@@ -2717,7 +2709,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
document.network_interface.set_input(
&InputConnector::node_at_index(*node_id, 0),
NodeInput::type_default(concrete!(graphene_std::vector::Vector), true),
NodeInput::type_default(descriptor!(graphene_std::vector::Vector), true),
network_path,
);
@@ -2767,7 +2759,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
.input_from_connector(&InputConnector::node_at_index(*node_id, index), network_path)
.is_some_and(|stored_input| match stored_input {
NodeInput::Value { tagged_value, .. } => match &**tagged_value {
TaggedValue::TypeDefault(stored_type) if matches!(stored_type, Type::Record(_)) && !tagged_value.is_no_paint() => {
// Our type defaults name their type rather than carrying a structural rank, so a list-carrying wire is recognized by its name.
TaggedValue::TypeDefault(stored_type) if stored_type.name.contains("list::List<") && !tagged_value.is_no_paint() => {
!matches!(definition_input, NodeInput::Value { tagged_value, .. } if matches!(&**tagged_value, TaggedValue::TypeDefault(definition_type) if definition_type == stored_type))
}
_ => false,
@@ -2905,11 +2898,15 @@ fn migrate_removed_catalog_definitions(node_id: &NodeId, node: &DocumentNode, ne
if let Some(DefinitionIdentifier::Network(name)) = document.network_interface.reference(node_id, network_path)
&& name == "Upload Texture"
{
let mut node_template = resolve_proto_node_type(graphene_std::platform_application_io::upload_texture::IDENTIFIER)?.default_node_template();
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
if let Some(content) = old_inputs.first() {
document.network_interface.set_input(&InputConnector::node_at_index(*node_id, 0), content.clone(), network_path);
// Our `upload_texture` node belongs to the optional wgpu-executor crate rather than to platform_application_io, so the conversion only exists in a GPU build.
#[cfg(feature = "gpu")]
{
let mut node_template = resolve_proto_node_type(wgpu_executor::texture_conversion::upload_texture::IDENTIFIER)?.default_node_template();
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
if let Some(content) = old_inputs.first() {
document.network_interface.set_input(&InputConnector::node_at_index(*node_id, 0), content.clone(), network_path);
}
}
}

View File

@@ -582,7 +582,7 @@ mod test_artboard {
Err(e) => panic!("Failed to evaluate graph: {e}"),
};
let mut artboards = List::new();
for list in instrumented.grab_all_input::<graphene_std::graphic::extend::NewInput<Artboard>, List<Artboard>>(&editor.runtime) {
for list in instrumented.grab_all_input::<graphene_std::graphic::extend::NewInput, List<Artboard>>(&editor.runtime) {
for index in 0..list.len() {
if let Some(item) = list.clone_item(index) {
artboards.push(item);

View File

@@ -388,7 +388,7 @@ const ATTR_PAINT_ORDER: &str = "paint_order";
/// `Vector::stroke` is gone upstream. In our paint model a lane's stroke is the `ATTR_STROKE`
/// `List<Graphic>`, so the stroke's GEOMETRY parameters ride that list's own attribute columns, on the
/// same names master's `Coverage` uses. Mirrors `vector_nodes::stroke_params`, which writes them.
fn stroke_params(paint: &List<Graphic>) -> StrokeStyle {
pub fn stroke_params(paint: &List<Graphic>) -> StrokeStyle {
let defaults = StrokeStyle::default();
StrokeStyle {
weight: paint.attribute_cloned_or(ATTR_WEIGHT, 0, defaults.weight),

View File

@@ -29,25 +29,21 @@ pub(crate) fn generate_node_input_references(
let struct_name = format_ident!("{}Input", input_ident.ident.to_string().to_case(Case::Pascal));
let (fn_generic_params, phantom_data_declerations) = generate_phantom_data(used.iter());
// Only create structs with phantom data where necessary.
generated_input_accessor.push(if phantom_data_declerations.is_empty() {
quote! {
pub struct #struct_name;
}
} else {
quote! {
pub struct #struct_name <#(#used),*>{
#(#phantom_data_declerations,)*
}
}
});
// The marker is always a unit struct so it can be passed as a value; its generics would only have described
// `Result`, which nothing reads through the marker.
let _ = &phantom_data_declerations;
generated_input_accessor.push(quote! {
impl <#(#used),*> #core_types::NodeInputDecleration for #struct_name <#(#fn_generic_params),*> {
pub struct #struct_name;
});
let result_ty = if used.is_empty() { quote!(#ty) } else { quote!(()) };
let _ = &fn_generic_params;
generated_input_accessor.push(quote! {
impl #core_types::NodeInputDecleration for #struct_name {
const INDEX: usize = #input_index;
fn identifier() -> #core_types::ProtoNodeIdentifier {
#inputs_module_name::IDENTIFIER.clone()
}
type Result = #ty;
type Result = #result_ty;
}
})
}

View File

@@ -393,10 +393,11 @@ fn fill<'e>(
_backup_gradient: IList<Gradient>,
_gradient_form: GradientForm,
_gradient_spread: GradientSpread,
_transform: Option<DAffine2>,
_has_transform: bool,
_transform: DAffine2,
) -> Result<(Vector, Attr<'e, Fill>), Interrupt> {
let mut paint = paint_table(paint);
default_gradient_paint(&mut paint, element.bounding_box(), _gradient_form, _gradient_spread, _transform);
default_gradient_paint(&mut paint, element.bounding_box(), _gradient_form, _gradient_spread, _has_transform.then_some(_transform));
let parked = park_paint(ctx.arena(), paint)?;
Ok((element, Attr(Some(parked))))
}
@@ -413,14 +414,15 @@ fn fill_graphic_leveled<'e>(
_backup_gradient: IList<Gradient>,
_gradient_form: GradientForm,
_gradient_spread: GradientSpread,
_transform: Option<DAffine2>,
_has_transform: bool,
_transform: DAffine2,
) -> Result<(Graphic<'static>, Attr<'e, Fill>), Interrupt> {
let bounds = match BoundingBox::bounding_box(&element, DAffine2::IDENTITY, false) {
RenderBoundingBox::Rectangle(bounds) => Some(bounds),
_ => None,
};
let mut paint = paint_table(paint);
default_gradient_paint(&mut paint, bounds, _gradient_form, _gradient_spread, _transform);
default_gradient_paint(&mut paint, bounds, _gradient_form, _gradient_spread, _has_transform.then_some(_transform));
let parked = park_paint(ctx.arena(), paint)?;
Ok((element, Attr(Some(parked))))
}