Replace the IntoPaint trait with direct Graphic-typed node inputs (#4442)

This commit is contained in:
Keavon Chambers
2026-09-15 17:50:14 +02:00
committed by Dennis Kobert
parent a41fdb3d75
commit 03262e1bab
18 changed files with 44 additions and 67 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -103,6 +103,7 @@ pub struct DocumentMessageHandler {
pub properties_panel_collapsed_sections: Vec<NodeId>, pub properties_panel_collapsed_sections: Vec<NodeId>,
/// The full Git commit hash of the Graphite repository that was used to build the editor. /// The full Git commit hash of the Graphite repository that was used to build the editor.
/// We save this to provide a hint about which version of the editor was used to create the document. /// We save this to provide a hint about which version of the editor was used to create the document.
#[serde(skip_deserializing, default)]
pub commit_hash: String, pub commit_hash: String,
/// The current pan, tilt, and zoom state of the viewport's view of the document canvas. /// The current pan, tilt, and zoom state of the viewport's view of the document canvas.
pub document_ptz: PTZ, pub document_ptz: PTZ,
@@ -435,7 +435,7 @@ impl<'a> ModifyInputsContext<'a> {
let Some(fill_node_id) = self.existing_chain_hosted_node_id(graphene_std::vector_nodes::fill::IDENTIFIER, true) else { let Some(fill_node_id) = self.existing_chain_hosted_node_id(graphene_std::vector_nodes::fill::IDENTIFIER, true) else {
return; return;
}; };
let input_connector = InputConnector::node(fill_node_id, graphene_std::vector::fill::FillInput); let input_connector = InputConnector::node(fill_node_id, graphene_std::vector::fill::PaintInput);
let backup_input_connector = InputConnector::node(fill_node_id, graphene_std::vector::fill::BackupColorInput); let backup_input_connector = InputConnector::node(fill_node_id, graphene_std::vector::fill::BackupColorInput);
// The backup remembers the last solid color, so the red-slash "none" choice leaves it untouched // The backup remembers the last solid color, so the red-slash "none" choice leaves it untouched
@@ -457,7 +457,7 @@ impl<'a> ModifyInputsContext<'a> {
// Skip the rerender on all but the last input so the whole update triggers a single graph run // Skip the rerender on all but the last input so the whole update triggers a single graph run
self.set_input_with_refresh( self.set_input_with_refresh(
InputConnector::node(fill_node_id, graphene_std::vector::fill::FillInput), InputConnector::node(fill_node_id, graphene_std::vector::fill::PaintInput),
NodeInput::value(TaggedValue::GradientRamp(ramp), false), NodeInput::value(TaggedValue::GradientRamp(ramp), false),
true, true,
); );
@@ -1762,7 +1762,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
let is_text_node = reference.as_ref().is_some_and(|r| *r == DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER)); let is_text_node = reference.as_ref().is_some_and(|r| *r == DefinitionIdentifier::ProtoNode(graphene_std::text::text::IDENTIFIER));
let is_stroke_node = reference.as_ref().is_some_and(|r| *r == DefinitionIdentifier::ProtoNode(graphene_std::vector::stroke::IDENTIFIER)); let is_stroke_node = reference.as_ref().is_some_and(|r| *r == DefinitionIdentifier::ProtoNode(graphene_std::vector::stroke::IDENTIFIER));
let is_fill_node = reference.as_ref().is_some_and(|r| *r == DefinitionIdentifier::ProtoNode(graphene_std::vector::fill::IDENTIFIER)); let is_fill_node = reference.as_ref().is_some_and(|r| *r == DefinitionIdentifier::ProtoNode(graphene_std::vector::fill::IDENTIFIER));
let is_fill_input = is_fill_node && input_index == graphene_std::vector::fill::FillInput::INDEX; let is_fill_input = is_fill_node && input_index == graphene_std::vector::fill::PaintInput::INDEX;
let is_shape_generator_node = reference.as_ref().is_some_and(|r| { let is_shape_generator_node = reference.as_ref().is_some_and(|r| {
[regular_polygon::IDENTIFIER, star::IDENTIFIER, arc::IDENTIFIER, spiral::IDENTIFIER, grid::IDENTIFIER, arrow::IDENTIFIER] [regular_polygon::IDENTIFIER, star::IDENTIFIER, arc::IDENTIFIER, spiral::IDENTIFIER, grid::IDENTIFIER, arrow::IDENTIFIER]
.into_iter() .into_iter()
@@ -2418,9 +2418,9 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
} }
// Pass blank_assist=false because the assist slot is filled below ("Reverse Stops" button when in gradient mode) // Pass blank_assist=false because the assist slot is filled below ("Reverse Stops" button when in gradient mode)
let mut widgets_first_row = start_widgets(&ParameterWidgetsInfo::new(node_id, FillInput, false, context)); let mut widgets_first_row = start_widgets(&ParameterWidgetsInfo::new(node_id, PaintInput, false, context));
if get_document_node(node_id, context).is_ok_and(|node| node.input(FillInput).is_some_and(|input| input.is_exposed())) { if get_document_node(node_id, context).is_ok_and(|node| node.input(PaintInput).is_some_and(|input| input.is_exposed())) {
return vec![LayoutGroup::row(widgets_first_row)]; return vec![LayoutGroup::row(widgets_first_row)];
} }
@@ -2429,7 +2429,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
let layer = root_layer_for_chain_node(node_id, context); let layer = root_layer_for_chain_node(node_id, context);
let fill = match get_document_node(node_id, context) { let fill = match get_document_node(node_id, context) {
Ok(document_node) => match document_node.input_value(FillInput) { Ok(document_node) => match document_node.input_value(PaintInput) {
Some(TaggedValue::Color(color)) => ResolvedFill::Solid(Some(*color)), Some(TaggedValue::Color(color)) => ResolvedFill::Solid(Some(*color)),
Some(value) if value.is_no_paint() => ResolvedFill::Solid(None), Some(value) if value.is_no_paint() => ResolvedFill::Solid(None),
Some(TaggedValue::GradientRamp(_)) => { Some(TaggedValue::GradientRamp(_)) => {
@@ -2477,7 +2477,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
.on_update(update_value( .on_update(update_value(
move |_| TaggedValue::GradientRamp(GradientRamp::from(stops.reversed(settings.cyclic)).with_settings(settings)), move |_| TaggedValue::GradientRamp(GradientRamp::from(stops.reversed(settings.cyclic)).with_settings(settings)),
node_id, node_id,
FillInput, PaintInput,
)) ))
.widget_instance(); .widget_instance();
widgets_first_row.push(Separator::new(SeparatorStyle::Unrelated).widget_instance()); widgets_first_row.push(Separator::new(SeparatorStyle::Unrelated).widget_instance());
@@ -2502,7 +2502,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
let mut messages = vec![ let mut messages = vec![
NodeGraphMessage::SetInputValue { NodeGraphMessage::SetInputValue {
node_id, node_id,
input_index: FillInput::INDEX, input_index: PaintInput::INDEX,
value: color.map_or_else(TaggedValue::no_paint, TaggedValue::Color).into(), value: color.map_or_else(TaggedValue::no_paint, TaggedValue::Color).into(),
} }
.into(), .into(),
@@ -2524,7 +2524,7 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
messages: Box::new([ messages: Box::new([
NodeGraphMessage::SetInputValue { NodeGraphMessage::SetInputValue {
node_id, node_id,
input_index: FillInput::INDEX, input_index: PaintInput::INDEX,
value: Box::new(TaggedValue::GradientRamp(ramp.clone())), value: Box::new(TaggedValue::GradientRamp(ramp.clone())),
} }
.into(), .into(),
@@ -2562,11 +2562,11 @@ pub(crate) fn fill_properties(node_id: NodeId, context: &mut NodePropertiesConte
let entries = vec![ let entries = vec![
RadioEntryData::new("solid") RadioEntryData::new("solid")
.label("Solid") .label("Solid")
.on_update(update_value(move |_| backup_color.map_or_else(TaggedValue::no_paint, TaggedValue::Color), node_id, FillInput)) .on_update(update_value(move |_| backup_color.map_or_else(TaggedValue::no_paint, TaggedValue::Color), node_id, PaintInput))
.on_commit(commit_value), .on_commit(commit_value),
RadioEntryData::new("gradient") RadioEntryData::new("gradient")
.label("Gradient") .label("Gradient")
.on_update(update_value(move |_| TaggedValue::GradientRamp(backup_gradient.clone()), node_id, FillInput)) .on_update(update_value(move |_| TaggedValue::GradientRamp(backup_gradient.clone()), node_id, PaintInput))
.on_commit(commit_value), .on_commit(commit_value),
]; ];
@@ -725,7 +725,7 @@ fn find_fill_node(document: &DocumentMessageHandler) -> (Vec<graph_craft::docume
fn fill_paint_value(document: &DocumentMessageHandler) -> graph_craft::document::value::TaggedValue { fn fill_paint_value(document: &DocumentMessageHandler) -> graph_craft::document::value::TaggedValue {
let (network_path, node_id) = find_fill_node(document); let (network_path, node_id) = find_fill_node(document);
let network = document.network_interface.nested_network(&network_path).expect("the found network path should resolve"); let network = document.network_interface.nested_network(&network_path).expect("the found network path should resolve");
let input = network.nodes[&node_id].input(graphene_std::vector::fill::FillInput).expect("Fill should have a paint input"); let input = network.nodes[&node_id].input(graphene_std::vector::fill::PaintInput).expect("Fill should have a paint input");
input.as_value().expect("the paint input should hold a value").clone() input.as_value().expect("the paint input should hold a value").clone()
} }
@@ -740,7 +740,7 @@ async fn none_fill_survives_document_reopen() {
editor editor
.handle_message(NodeGraphMessage::SetInputValue { .handle_message(NodeGraphMessage::SetInputValue {
node_id: fill_node_id, node_id: fill_node_id,
input_index: graphene_std::vector::fill::FillInput::INDEX, input_index: graphene_std::vector::fill::PaintInput::INDEX,
value: Box::new(graph_craft::document::value::TaggedValue::no_paint()), value: Box::new(graph_craft::document::value::TaggedValue::no_paint()),
}) })
.await; .await;
@@ -785,7 +785,7 @@ async fn legacy_four_input_fill_migrates_to_the_split_transform_shape() {
let fill_node = &network.nodes[&node_id]; let fill_node = &network.nodes[&node_id];
assert_eq!(fill_node.inputs.len(), 7, "the legacy Fill should upgrade to the 7-input shape"); assert_eq!(fill_node.inputs.len(), 7, "the legacy Fill should upgrade to the 7-input shape");
let paint = fill_node.input(graphene_std::vector::fill::FillInput); let paint = fill_node.input(graphene_std::vector::fill::PaintInput);
assert!( assert!(
matches!(paint, Some(graph_craft::document::NodeInput::Node { .. })), matches!(paint, Some(graph_craft::document::NodeInput::Node { .. })),
"the wired legacy fill should keep its connection, but became {paint:?}" "the wired legacy fill should keep its connection, but became {paint:?}"
@@ -844,7 +844,7 @@ async fn eight_input_fill_migrates_the_spread_input_into_the_ramp() {
assert_eq!(fill_node.inputs.len(), 7, "the eight-input Fill should fold down to the 7-input shape"); assert_eq!(fill_node.inputs.len(), 7, "the eight-input Fill should fold down to the 7-input shape");
let paint = fill_node.input_value(graphene_std::vector::fill::FillInput); let paint = fill_node.input_value(graphene_std::vector::fill::PaintInput);
let Some(TaggedValue::GradientRamp(ramp)) = paint else { let Some(TaggedValue::GradientRamp(ramp)) = paint else {
panic!("the fill input should keep its gradient ramp value, but became {paint:?}"); panic!("the fill input should keep its gradient ramp value, but became {paint:?}");
}; };
@@ -272,14 +272,14 @@ pub fn get_viewport_center(layer: LayerNodeIdentifier, network_interface: &NodeN
pub fn get_fill_node_id_with_direct_fill_input(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> { pub fn get_fill_node_id_with_direct_fill_input(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
let fill_node_id = NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector::fill::IDENTIFIER))?; let fill_node_id = NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector::fill::IDENTIFIER))?;
let fill_node = network_interface.document_network().nodes.get(&fill_node_id)?; let fill_node = network_interface.document_network().nodes.get(&fill_node_id)?;
matches!(fill_node.input(graphene_std::vector::fill::FillInput)?, NodeInput::Value { .. }).then_some(fill_node_id) matches!(fill_node.input(graphene_std::vector::fill::PaintInput)?, NodeInput::Value { .. }).then_some(fill_node_id)
} }
/// Determine the input connector where the gradient chain enters the layer. /// Determine the input connector where the gradient chain enters the layer.
/// Returns Fill's fill input if the layer has a "Fill" node, otherwise returns the layer's content input. /// Returns Fill's fill input if the layer has a "Fill" node, otherwise returns the layer's content input.
pub fn gradient_chain_target_input(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> InputConnector { pub fn gradient_chain_target_input(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> InputConnector {
if let Some(fill_node_id) = NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector::fill::IDENTIFIER)) { if let Some(fill_node_id) = NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector::fill::IDENTIFIER)) {
InputConnector::node(fill_node_id, graphene_std::vector::fill::FillInput) InputConnector::node(fill_node_id, graphene_std::vector::fill::PaintInput)
} else { } else {
InputConnector::layer_secondary_input(layer.to_node()) InputConnector::layer_secondary_input(layer.to_node())
} }
@@ -382,7 +382,7 @@ pub fn get_upstream_color_value_node_id(layer: LayerNodeIdentifier, network_inte
pub fn get_fill_input_node_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> { pub fn get_fill_input_node_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<NodeId> {
let fill_node_id = NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector::fill::IDENTIFIER))?; let fill_node_id = NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector::fill::IDENTIFIER))?;
let fill_node = network_interface.document_network().nodes.get(&fill_node_id)?; let fill_node = network_interface.document_network().nodes.get(&fill_node_id)?;
let NodeInput::Node { node_id, .. } = fill_node.input(graphene_std::vector::fill::FillInput)? else { let NodeInput::Node { node_id, .. } = fill_node.input(graphene_std::vector::fill::PaintInput)? else {
return None; return None;
}; };
Some(*node_id) Some(*node_id)
@@ -410,7 +410,7 @@ pub fn get_gradient_stops(layer: LayerNodeIdentifier, network_interface: &NodeNe
.document_network() .document_network()
.nodes .nodes
.get(&fill_node_id) .get(&fill_node_id)
.and_then(|node| node.input(graphene_std::vector::fill::FillInput)) .and_then(|node| node.input(graphene_std::vector::fill::PaintInput))
.and_then(|input| input.as_value()) .and_then(|input| input.as_value())
.and_then(|value| if let TaggedValue::GradientRamp(ramp) = value { Some(Gradient::from(ramp)) } else { None }); .and_then(|value| if let TaggedValue::GradientRamp(ramp) = value { Some(Gradient::from(ramp)) } else { None });
} }
@@ -499,7 +499,7 @@ pub fn gradient_orientation_rightward(transform: glam::DAffine2) -> bool {
/// Get the current fill of a layer from the closest "Fill" node. /// Get the current fill of a layer from the closest "Fill" node.
pub fn get_fill_color(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<Color> { pub fn get_fill_color(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<Color> {
let TaggedValue::Color(color) = NodeGraphLayer::new(layer, network_interface).parameter_value(graphene_std::vector::fill::FillInput)? else { let TaggedValue::Color(color) = NodeGraphLayer::new(layer, network_interface).parameter_value(graphene_std::vector::fill::PaintInput)? else {
return None; return None;
}; };
Some(*color) Some(*color)
@@ -767,7 +767,7 @@ pub struct FillNodeGradient {
pub fn read_fill_node_gradient(fill_node: &DocumentNode, bounding_box: impl FnOnce() -> [DVec2; 2]) -> Option<FillNodeGradient> { pub fn read_fill_node_gradient(fill_node: &DocumentNode, bounding_box: impl FnOnce() -> [DVec2; 2]) -> Option<FillNodeGradient> {
use graphene_std::vector::fill; use graphene_std::vector::fill;
let TaggedValue::GradientRamp(ramp) = fill_node.input(fill::FillInput)?.as_value()? else { let TaggedValue::GradientRamp(ramp) = fill_node.input(fill::PaintInput)?.as_value()? else {
return None; return None;
}; };
let settings = GradientSettings::from(ramp); let settings = GradientSettings::from(ramp);
@@ -840,7 +840,7 @@ pub fn selected_fill_state(document: &DocumentMessageHandler) -> Option<Selected
let fill_choice = (|| { let fill_choice = (|| {
let fill_node = document.network_interface.document_network().nodes.get(&fill_node_id)?; let fill_node = document.network_interface.document_network().nodes.get(&fill_node_id)?;
match fill_node.input(graphene_std::vector::fill::FillInput)?.as_value()? { match fill_node.input(graphene_std::vector::fill::PaintInput)?.as_value()? {
TaggedValue::Color(color) => Some(FillChoice::Solid(*color)), TaggedValue::Color(color) => Some(FillChoice::Solid(*color)),
TaggedValue::GradientRamp(ramp) => Some(FillChoice::Gradient(ramp.clone())), TaggedValue::GradientRamp(ramp) => Some(FillChoice::Gradient(ramp.clone())),
value if value.is_no_paint() => Some(FillChoice::None), value if value.is_no_paint() => Some(FillChoice::None),
@@ -269,7 +269,7 @@ mod test_fill {
}; };
instrumented instrumented
.grab_all_input_level::<fill::FillInput, Color>(&editor.runtime) .grab_all_input_level::<fill::PaintInput, Color>(&editor.runtime)
.flat_map(|list| list.iter_element_values().cloned().collect::<Vec<_>>()) .flat_map(|list| list.iter_element_values().cloned().collect::<Vec<_>>())
.collect() .collect()
} }
@@ -498,7 +498,7 @@ mod test_fill {
let ellipse_fill_id = get_fill_node_id_with_direct_fill_input(ellipse, &editor.active_document().network_interface).expect("the ellipse should have a Fill node"); let ellipse_fill_id = get_fill_node_id_with_direct_fill_input(ellipse, &editor.active_document().network_interface).expect("the ellipse should have a Fill node");
editor.active_document_mut().network_interface.create_wire( editor.active_document_mut().network_interface.create_wire(
&OutputConnector::primary_output(shared_transform_id), &OutputConnector::primary_output(shared_transform_id),
&InputConnector::node(ellipse_fill_id, graphene_std::vector::fill::FillInput), &InputConnector::node(ellipse_fill_id, graphene_std::vector::fill::PaintInput),
&[], &[],
); );
@@ -518,7 +518,7 @@ mod test_fill {
assert_eq!( assert_eq!(
document document
.network_interface .network_interface
.upstream_output_connector(&InputConnector::node(ellipse_fill_id, graphene_std::vector::fill::FillInput), &[]) .upstream_output_connector(&InputConnector::node(ellipse_fill_id, graphene_std::vector::fill::PaintInput), &[])
.and_then(|output| output.node_id()), .and_then(|output| output.node_id()),
Some(shared_transform_id), Some(shared_transform_id),
"the ellipse should keep being painted by the shared chain" "the ellipse should keep being painted by the shared chain"
@@ -2165,7 +2165,7 @@ mod test_gradient {
let fill_node_id = get_fill_node_id_with_direct_fill_input(layer, &document.network_interface)?; let fill_node_id = get_fill_node_id_with_direct_fill_input(layer, &document.network_interface)?;
let fill_node = document.network_interface.document_network().nodes.get(&fill_node_id)?; let fill_node = document.network_interface.document_network().nodes.get(&fill_node_id)?;
let (stops, gradient_spread) = match fill_node.input(fill::FillInput)?.as_value()? { let (stops, gradient_spread) = match fill_node.input(fill::PaintInput)?.as_value()? {
TaggedValue::GradientRamp(ramp) => (Gradient::from(ramp), ramp.gradient_spread), TaggedValue::GradientRamp(ramp) => (Gradient::from(ramp), ramp.gradient_spread),
_ => return None, _ => return None,
}; };
@@ -2305,7 +2305,7 @@ mod test_gradient {
editor editor
.handle_message(NodeGraphMessage::CreateWire { .handle_message(NodeGraphMessage::CreateWire {
output_connector: OutputConnector::primary_output(gradient_node_id), output_connector: OutputConnector::primary_output(gradient_node_id),
input_connector: InputConnector::node(fill_node_id, fill::FillInput), input_connector: InputConnector::node(fill_node_id, fill::PaintInput),
}) })
.await; .await;
@@ -3031,7 +3031,7 @@ mod test_gradient {
editor editor
.handle_message(NodeGraphMessage::CreateWire { .handle_message(NodeGraphMessage::CreateWire {
output_connector: OutputConnector::primary_output(gradient_value_id), output_connector: OutputConnector::primary_output(gradient_value_id),
input_connector: InputConnector::node(fill_node_id, graphene_std::vector::fill::FillInput), input_connector: InputConnector::node(fill_node_id, graphene_std::vector::fill::PaintInput),
}) })
.await; .await;
editor editor
@@ -6,8 +6,6 @@ use canvas_utils::{Canvas, CanvasHandle};
use core_types::attribute::{Attr, OwnedAttr, Transform}; use core_types::attribute::{Attr, OwnedAttr, Transform};
use core_types::color::SRGBA8; use core_types::color::SRGBA8;
use core_types::gpoll::GPoll; use core_types::gpoll::GPoll;
#[cfg(target_family = "wasm")]
use core_types::list::List;
#[cfg(target_family = "wasm")] #[cfg(target_family = "wasm")]
use core_types::ATTR_TRANSFORM; use core_types::ATTR_TRANSFORM;
@@ -25,16 +23,10 @@ pub use graphene_canvas_utils as canvas_utils;
#[cfg(target_family = "wasm")] #[cfg(target_family = "wasm")]
use graphic_types::Graphic; use graphic_types::Graphic;
#[cfg(target_family = "wasm")] #[cfg(target_family = "wasm")]
use graphic_types::IntoGraphicList;
#[cfg(target_family = "wasm")]
use graphic_types::Vector;
#[cfg(target_family = "wasm")]
use graphic_types::markers::EditorMergedLayers; use graphic_types::markers::EditorMergedLayers;
use graphic_types::raster_types::Image; use graphic_types::raster_types::Image;
use graphic_types::raster_types::{CPU, GPU, Raster}; use graphic_types::raster_types::{CPU, GPU, Raster};
#[cfg(target_family = "wasm")] #[cfg(target_family = "wasm")]
use graphic_types::vector_types::gradient::Gradient;
#[cfg(target_family = "wasm")]
use rendering::{Render, RenderParams, RenderSvgSegmentList, SvgRender}; use rendering::{Render, RenderParams, RenderSvgSegmentList, SvgRender};
use std::sync::Arc; use std::sync::Arc;
@@ -204,23 +196,7 @@ fn create_canvas(_: impl Ctx) -> CanvasHandle {
/// Renders a view of the input graphic within an area defined by the *Footprint*. /// Renders a view of the input graphic within an area defined by the *Footprint*.
#[cfg(target_family = "wasm")] #[cfg(target_family = "wasm")]
#[node_macro::node(category(""))] #[node_macro::node(category(""))]
async fn rasterize<T: Clone + Send + Sync + dyn_any::StaticTypeSized>( async fn rasterize(_: impl Ctx, _: (), mut data: IList<Graphic<'static>>, footprint: Footprint, mut canvas: CanvasHandle) -> (Raster<CPU>, Attr<Transform>, OwnedAttr<EditorMergedLayers>) {
_: impl Ctx,
_: (),
#[implementations(
Vector,
Raster<CPU>,
Graphic,
Color,
Gradient,
)]
mut data: IList<T>,
footprint: Footprint,
mut canvas: CanvasHandle,
) -> (Raster<CPU>, Attr<Transform>, OwnedAttr<EditorMergedLayers>)
where
List<T>: Render + Clone + IntoGraphicList,
{
use glam::{DAffine2, DVec2}; use glam::{DAffine2, DVec2};
if footprint.transform.matrix2.determinant() == 0. { if footprint.transform.matrix2.determinant() == 0. {
@@ -232,7 +208,7 @@ where
// Snapshot the input as a List<Graphic> so the renderer can recurse into the original child layers // Snapshot the input as a List<Graphic> so the renderer can recurse into the original child layers
// when collecting metadata, exposing their click targets to editor tools (same mechanism as Boolean Operation). // when collecting metadata, exposing their click targets to editor tools (same mechanism as Boolean Operation).
// The copy is owned before the first await: the input's arena content dies with the spawning evaluation. // The copy is owned before the first await: the input's arena content dies with the spawning evaluation.
let upstream_graphic_list = data.clone().into_graphic_list(); let upstream_graphic_list = data.clone();
let merged_layers = OwnedAttr::new(Some(&upstream_graphic_list)); let merged_layers = OwnedAttr::new(Some(&upstream_graphic_list));
let mut render = SvgRender::new(); let mut render = SvgRender::new();
+5 -5
View File
@@ -350,16 +350,16 @@ fn fill<'e>(
ctx: impl Ctx + ExtractArena<'e> + ExtractIndex + InjectIndex + Copy, ctx: impl Ctx + ExtractArena<'e> + ExtractIndex + InjectIndex + Copy,
/// The content with vector paths to apply the fill style to. /// The content with vector paths to apply the fill style to.
(element, content_appearance): (Vector, Attr<AppearanceMarker>), (element, content_appearance): (Vector, Attr<AppearanceMarker>),
/// The fill to paint the path with. /// The paint to fill the path's interior with.
#[default(Color::BLACK)] #[default(Color::BLACK)]
fill: IList<Graphic<'static>>, paint: IList<Graphic<'static>>,
_backup_color: IList<Color>, _backup_color: IList<Color>,
_backup_gradient: IList<Gradient>, _backup_gradient: IList<Gradient>,
_gradient_form: GradientForm, _gradient_form: GradientForm,
_has_transform: bool, _has_transform: bool,
_transform: DAffine2, _transform: DAffine2,
) -> Result<(Vector, Attr<'e, AppearanceMarker>), Interrupt> { ) -> Result<(Vector, Attr<'e, AppearanceMarker>), Interrupt> {
let mut paint = paint_table(fill); let mut paint = paint_table(paint);
default_gradient_paint(&mut paint, element.bounding_box(), _gradient_form, _has_transform.then_some(_transform)); default_gradient_paint(&mut paint, element.bounding_box(), _gradient_form, _has_transform.then_some(_transform));
let appearance = stamped_appearance(*content_appearance, Coverage::new_fill(), &paint, CoverPlacement::Above); let appearance = stamped_appearance(*content_appearance, Coverage::new_fill(), &paint, CoverPlacement::Above);
let parked_appearance = park_appearance(ctx.arena(), appearance)?; let parked_appearance = park_appearance(ctx.arena(), appearance)?;
@@ -372,7 +372,7 @@ fn fill<'e>(
fn fill_graphic_leveled<'e>( fn fill_graphic_leveled<'e>(
ctx: impl Ctx + ExtractArena<'e> + ExtractIndex + InjectIndex + Copy, ctx: impl Ctx + ExtractArena<'e> + ExtractIndex + InjectIndex + Copy,
(element, content_appearance): (Graphic<'static>, Attr<AppearanceMarker>), (element, content_appearance): (Graphic<'static>, Attr<AppearanceMarker>),
#[default(Color::BLACK)] fill: IList<Graphic<'static>>, #[default(Color::BLACK)] paint: IList<Graphic<'static>>,
_backup_color: IList<Color>, _backup_color: IList<Color>,
_backup_gradient: IList<Gradient>, _backup_gradient: IList<Gradient>,
_gradient_form: GradientForm, _gradient_form: GradientForm,
@@ -383,7 +383,7 @@ fn fill_graphic_leveled<'e>(
RenderBoundingBox::Rectangle(bounds) => Some(bounds), RenderBoundingBox::Rectangle(bounds) => Some(bounds),
_ => None, _ => None,
}; };
let mut paint = paint_table(fill); let mut paint = paint_table(paint);
default_gradient_paint(&mut paint, bounds, _gradient_form, _has_transform.then_some(_transform)); default_gradient_paint(&mut paint, bounds, _gradient_form, _has_transform.then_some(_transform));
let appearance = stamped_appearance(*content_appearance, Coverage::new_fill(), &paint, CoverPlacement::Above); let appearance = stamped_appearance(*content_appearance, Coverage::new_fill(), &paint, CoverPlacement::Above);
let parked_appearance = park_appearance(ctx.arena(), appearance)?; let parked_appearance = park_appearance(ctx.arena(), appearance)?;