This commit is contained in:
Dennis Kobert
2026-07-30 19:11:22 +02:00
parent e2a8420fee
commit f13806efcd
18 changed files with 60 additions and 71 deletions
+3 -3
View File
@@ -4,13 +4,13 @@ use crate::application_io::resource::Resource;
use crate::proto::Any as DAny; use crate::proto::Any as DAny;
use brush_nodes::brush_stroke::BrushStroke; use brush_nodes::brush_stroke::BrushStroke;
use core_types::color::SRGBA8; use core_types::color::SRGBA8;
use core_types::list::List;
use core_types::transform::Footprint;
use core_types::uuid::NodeId;
use core_types::context::Context; use core_types::context::Context;
use core_types::gnode::GNode; use core_types::gnode::GNode;
use core_types::gpoll::GPoll; use core_types::gpoll::GPoll;
use core_types::list::List;
use core_types::registry::{EdgeHandle, edge_type}; use core_types::registry::{EdgeHandle, edge_type};
use core_types::transform::Footprint;
use core_types::uuid::NodeId;
use core_types::value::value_edge; use core_types::value::value_edge;
use core_types::{CacheHash, Color, ContextModification, MemoHash, Node, Type, TypeDescriptor}; use core_types::{CacheHash, Color, ContextModification, MemoHash, Node, Type, TypeDescriptor};
use dyn_any::DynAny; use dyn_any::DynAny;
@@ -459,10 +459,10 @@ impl BorrowTree {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use graph_craft::document::value::TaggedValue;
use core_types::arena::ArenaCell; use core_types::arena::ArenaCell;
use core_types::context::{ExtractFootprint, ExtractVarArgs}; use core_types::context::{ExtractFootprint, ExtractVarArgs};
use core_types::runtime::{SourceFuture, Spawner}; use core_types::runtime::{SourceFuture, Spawner};
use graph_craft::document::value::TaggedValue;
struct InertSpawner; struct InertSpawner;
@@ -13,12 +13,12 @@ use graphene_std::raster::GPU;
use graphene_std::raster::color::Color; use graphene_std::raster::color::Color;
use graphene_std::raster::*; use graphene_std::raster::*;
use graphene_std::raster::{CPU, Raster}; use graphene_std::raster::{CPU, Raster};
use graphene_std::registry::{ConstructionError, EdgeHandle, ErasedGNode, NodeIOTypes, RegistryEntry};
use graphene_std::render_node::RenderIntermediate; use graphene_std::render_node::RenderIntermediate;
use graphene_std::runtime::RuntimeHandle;
use graphene_std::transform::Footprint; use graphene_std::transform::Footprint;
use graphene_std::uuid::NodeId; use graphene_std::uuid::NodeId;
use graphene_std::vector::Vector; use graphene_std::vector::Vector;
use graphene_std::registry::{ConstructionError, EdgeHandle, ErasedGNode, NodeIOTypes, RegistryEntry};
use graphene_std::runtime::RuntimeHandle;
use graphene_std::{Artboard, Context, Graphic, ProtoNodeIdentifier, SourceId, concrete, fn_type}; use graphene_std::{Artboard, Context, Graphic, ProtoNodeIdentifier, SourceId, concrete, fn_type};
use node_registry_macros::{async_node, convert_node, into_node}; use node_registry_macros::{async_node, convert_node, into_node};
use std::collections::HashMap; use std::collections::HashMap;
@@ -86,10 +86,7 @@ struct LendStringNode {
impl LendStringNode { impl LendStringNode {
fn new(value: String) -> Self { fn new(value: String) -> Self {
Self { Self { value, cell: ArenaCell::new() }
value,
cell: ArenaCell::new(),
}
} }
} }
+1 -4
View File
@@ -168,10 +168,7 @@ impl StatusCell {
} }
pub fn no_partial() -> Self { pub fn no_partial() -> Self {
Self { Self { no_partial: true, ..Self::new() }
no_partial: true,
..Self::new()
}
} }
pub fn eval_input<Input, N: GNode<Input>>(&self, input_index: usize, node: &N, input: &Input) -> Result<N::Output, Interrupt> { pub fn eval_input<Input, N: GNode<Input>>(&self, input_index: usize, node: &N, input: &Input) -> Result<N::Output, Interrupt> {
@@ -117,10 +117,7 @@ impl<N: ?Sized> SharedEdge<N> {
} }
pub fn share(&self) -> Self { pub fn share(&self) -> Self {
Self { Self { ptr: self.ptr, own: self.own.clone() }
ptr: self.ptr,
own: self.own.clone(),
}
} }
} }
@@ -152,12 +149,7 @@ where
unsafe { self.ptr.as_ref() }.serialize() unsafe { self.ptr.as_ref() }.serialize()
} }
fn eval_batch<'a>( fn eval_batch<'a>(&self, input: &'a Input, range: std::ops::Range<u64>, scratch: Option<&'a mut [std::mem::MaybeUninit<Self::Output>]>) -> crate::gnode::BatchStatus<'a, Self::Output>
&self,
input: &'a Input,
range: std::ops::Range<u64>,
scratch: Option<&'a mut [std::mem::MaybeUninit<Self::Output>]>,
) -> crate::gnode::BatchStatus<'a, Self::Output>
where where
Input: crate::context::InjectIndex + Copy, Input: crate::context::InjectIndex + Copy,
{ {
@@ -235,10 +227,7 @@ impl EdgeHandle {
pub fn downcast_erased<N: ?Sized + 'static>(self, expected: Type) -> Result<SharedEdge<N>, ConstructionError> { pub fn downcast_erased<N: ?Sized + 'static>(self, expected: Type) -> Result<SharedEdge<N>, ConstructionError> {
let found = self.ty; let found = self.ty;
self.node self.node.downcast::<SharedEdge<N>>().map(|edge| *edge).map_err(|_| ConstructionError::Type { expected, found })
.downcast::<SharedEdge<N>>()
.map(|edge| *edge)
.map_err(|_| ConstructionError::Type { expected, found })
} }
} }
@@ -364,7 +353,7 @@ mod tests {
#[test] #[test]
fn derive_ctx_repeat_pushes_index_levels_through_the_erased_edge() { fn derive_ctx_repeat_pushes_index_levels_through_the_erased_edge() {
use crate::context::{Derived, DeriveCtx, ExtractIndex}; use crate::context::{DeriveCtx, Derived, ExtractIndex};
struct RepeatNode<Node0> { struct RepeatNode<Node0> {
content: Node0, content: Node0,
@@ -421,7 +410,7 @@ mod tests {
#[test] #[test]
fn derive_ctx_footprint_replace_reaches_the_content() { fn derive_ctx_footprint_replace_reaches_the_content() {
use crate::context::{Derived, DeriveCtx, ExtractFootprint}; use crate::context::{DeriveCtx, Derived, ExtractFootprint};
use crate::transform::Footprint; use crate::transform::Footprint;
struct ShiftFootprintNode<Node0> { struct ShiftFootprintNode<Node0> {
@@ -300,12 +300,7 @@ mod tests {
let gate = Arc::new(std::sync::atomic::AtomicBool::new(false)); let gate = Arc::new(std::sync::atomic::AtomicBool::new(false));
let runtime = Arc::new(MockRuntime::default()); let runtime = Arc::new(MockRuntime::default());
let graph = StagedSumNode::new( let graph = StagedSumNode::new(SourceNode(40.0f64), GatedSource(gate.clone(), 2.0), SourceNode(RuntimeHandle(runtime.clone())), SourceNode(9u64));
SourceNode(40.0f64),
GatedSource(gate.clone(), 2.0),
SourceNode(RuntimeHandle(runtime.clone())),
SourceNode(9u64),
);
assert_eq!(GNode::eval(&graph, &ctx), GPoll::Pending); assert_eq!(GNode::eval(&graph, &ctx), GPoll::Pending);
assert_eq!(runtime.drain(), Vec::<SourceId>::new(), "an interrupted prologue must not spawn or claim the slot"); assert_eq!(runtime.drain(), Vec::<SourceId>::new(), "an interrupted prologue must not spawn or claim the slot");
@@ -9,11 +9,11 @@ use crate::texture_cache::TextureCache;
use anyhow::Result; use anyhow::Result;
use core_types::Color; use core_types::Color;
use core_types::color::SRGBA8; use core_types::color::SRGBA8;
use std::sync::Mutex;
use glam::UVec2; use glam::UVec2;
use graphene_application_io::{ApplicationIo, EditorApi}; use graphene_application_io::{ApplicationIo, EditorApi};
use raster_types::Texture; use raster_types::Texture;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex;
use vello::{AaConfig, AaSupport, RenderParams, Renderer, RendererOptions, Scene}; use vello::{AaConfig, AaSupport, RenderParams, Renderer, RendererOptions, Scene};
use wgpu::{Origin3d, TextureAspect}; use wgpu::{Origin3d, TextureAspect};
@@ -2,10 +2,10 @@ use crate::WgpuContext;
use crate::shader_runtime::{FULLSCREEN_VERTEX_SHADER_NAME, ShaderRuntime}; use crate::shader_runtime::{FULLSCREEN_VERTEX_SHADER_NAME, ShaderRuntime};
use core_types::list::{Item, List}; use core_types::list::{Item, List};
use core_types::shaders::buffer_struct::BufferStruct; use core_types::shaders::buffer_struct::BufferStruct;
use std::sync::Mutex;
use raster_types::{GPU, Raster}; use raster_types::{GPU, Raster};
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Mutex;
use wgpu::util::{BufferInitDescriptor, DeviceExt}; use wgpu::util::{BufferInitDescriptor, DeviceExt};
use wgpu::{ use wgpu::{
BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, Buffer, BufferBinding, BufferBindingType, BufferUsages, ColorTargetState, Face, BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, Buffer, BufferBinding, BufferBindingType, BufferUsages, ColorTargetState, Face,
@@ -1,4 +1,5 @@
use crate::WgpuExecutor; use crate::WgpuExecutor;
use crate::WgpuExecutorHandle;
use core_types::Color; use core_types::Color;
use core_types::Ctx; use core_types::Ctx;
use core_types::color::SRGBA8; use core_types::color::SRGBA8;
@@ -8,7 +9,6 @@ use core_types::runtime::SourceFuture;
use core_types::transform::Footprint; use core_types::transform::Footprint;
use raster_types::Image; use raster_types::Image;
use raster_types::{CPU, GPU, Raster}; use raster_types::{CPU, GPU, Raster};
use crate::WgpuExecutorHandle;
use wgpu::util::{DeviceExt, TextureDataOrder}; use wgpu::util::{DeviceExt, TextureDataOrder};
use wgpu::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages}; use wgpu::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages};
@@ -40,7 +40,6 @@ fn upload_to_texture(device: &wgpu::Device, queue: &wgpu::Queue, image: &Raster<
) )
} }
/// Passthrough conversion for GPU `List`s - no conversion needed /// Passthrough conversion for GPU `List`s - no conversion needed
impl Convert<List<Raster<GPU>>, WgpuExecutorHandle> for List<Raster<GPU>> { impl Convert<List<Raster<GPU>>, WgpuExecutorHandle> for List<Raster<GPU>> {
fn convert(self, _: Footprint, _converter: WgpuExecutorHandle) -> List<Raster<GPU>> { fn convert(self, _: Footprint, _converter: WgpuExecutorHandle) -> List<Raster<GPU>> {
+10 -10
View File
@@ -165,7 +165,10 @@ pub(crate) fn generate_gnode_code(crate_ident: &CrateIdent, parsed: &ParsedNodeF
} }
let clampable_bounds = regular_fields.iter().filter_map(|field| { let clampable_bounds = regular_fields.iter().filter_map(|field| {
let ParsedFieldType::Regular(RegularParsedField { ty, number_hard_min, number_hard_max, .. }) = &field.ty else { let ParsedFieldType::Regular(RegularParsedField {
ty, number_hard_min, number_hard_max, ..
}) = &field.ty
else {
return None; return None;
}; };
(number_hard_min.is_some() || number_hard_max.is_some()).then(|| quote!(#ty: #core_types::misc::Clampable)) (number_hard_min.is_some() || number_hard_max.is_some()).then(|| quote!(#ty: #core_types::misc::Clampable))
@@ -617,9 +620,7 @@ fn entries_tokens(parsed: &ParsedNodeFn, struct_name: &Ident, data_field_generic
let types = row.iter(); let types = row.iter();
let edge_types = row.iter().map(|ty| quote!(gcore::registry::SharedEdge<gcore::registry::ErasedGNode<#ty>>)); let edge_types = row.iter().map(|ty| quote!(gcore::registry::SharedEdge<gcore::registry::ErasedGNode<#ty>>));
let output = quote!(<#struct_name<#(#edge_types),*> as gcore::gnode::GNode<gcore::context::ContextImpl<'static>>>::Output); let output = quote!(<#struct_name<#(#edge_types),*> as gcore::gnode::GNode<gcore::context::ContextImpl<'static>>>::Output);
let downcasts = names.iter().zip(row.iter()).map(|(name, ty)| { let downcasts = names.iter().zip(row.iter()).map(|(name, ty)| quote!(let #name = inputs.next().unwrap().downcast::<#ty>()?;));
quote!(let #name = inputs.next().unwrap().downcast::<#ty>()?;)
});
quote! { quote! {
gcore::registry::RegistryEntry { gcore::registry::RegistryEntry {
io: gcore::registry::NodeIOTypes::new( io: gcore::registry::NodeIOTypes::new(
@@ -666,15 +667,14 @@ fn implementation_rows(parsed: &ParsedNodeFn, regular_fields: &[&ParsedField]) -
}, },
ParsedFieldType::Node(NodeParsedField { output_type, implementations, .. }) => match implementations.is_empty() { ParsedFieldType::Node(NodeParsedField { output_type, implementations, .. }) => match implementations.is_empty() {
false => Some(implementations.iter().map(|implementation| implementation.output.clone()).collect()), false => Some(implementations.iter().map(|implementation| implementation.output.clone()).collect()),
true => open_generics.iter().all(|generic| !crate::codegen::type_contains_ident(output_type, generic)).then(|| vec![output_type.clone()]), true => open_generics
.iter()
.all(|generic| !crate::codegen::type_contains_ident(output_type, generic))
.then(|| vec![output_type.clone()]),
}, },
}) })
.collect::<Option<_>>()?; .collect::<Option<_>>()?;
let row_count = candidates.iter().map(|types| types.len()).max().unwrap_or(1).max(1); let row_count = candidates.iter().map(|types| types.len()).max().unwrap_or(1).max(1);
Some( Some((0..row_count).map(|row| candidates.iter().map(|types| types[row.min(types.len() - 1)].clone()).collect()).collect())
(0..row_count)
.map(|row| candidates.iter().map(|types| types[row.min(types.len() - 1)].clone()).collect())
.collect(),
)
} }
+4 -1
View File
@@ -33,7 +33,10 @@ fn validate_async_source(parsed: &ParsedNodeFn) {
} }
if !parsed.is_async { if !parsed.is_async {
if snapshot_ctx { if snapshot_ctx {
emit_error!(parsed.input.pat_ident.span(), "`CtxSnapshot` is the async source context; synchronous nodes take `impl Ctx` and read through extract bounds"); emit_error!(
parsed.input.pat_ident.span(),
"`CtxSnapshot` is the async source context; synchronous nodes take `impl Ctx` and read through extract bounds"
);
} }
if !future_kernel { if !future_kernel {
return; return;
+7 -5
View File
@@ -1,5 +1,6 @@
use crate::brush_cache::BrushCache; use crate::brush_cache::BrushCache;
use crate::brush_stroke::{BrushStroke, BrushStyle}; use crate::brush_stroke::{BrushStroke, BrushStyle};
use core_types::Ctx;
use core_types::blending::BlendMode; use core_types::blending::BlendMode;
use core_types::bounds::{BoundingBox, RenderBoundingBox}; use core_types::bounds::{BoundingBox, RenderBoundingBox};
use core_types::color::{Alpha, Color, Pixel, Sample}; use core_types::color::{Alpha, Color, Pixel, Sample};
@@ -8,7 +9,6 @@ use core_types::math::bbox::{AxisAlignedBbox, Bbox};
use core_types::transform::Transform; use core_types::transform::Transform;
use core_types::uuid::NodeId; use core_types::uuid::NodeId;
use core_types::{ATTR_BLEND_MODE, ATTR_CLIPPING_MASK, ATTR_EDITOR_LAYER_PATH, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_TRANSFORM}; use core_types::{ATTR_BLEND_MODE, ATTR_CLIPPING_MASK, ATTR_EDITOR_LAYER_PATH, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_TRANSFORM};
use core_types::Ctx;
use glam::{DAffine2, DVec2}; use glam::{DAffine2, DVec2};
use raster_nodes::blending_nodes::blend_colors; use raster_nodes::blending_nodes::blend_colors;
use raster_nodes::std_nodes::{empty_image, extend_image_to_bounds}; use raster_nodes::std_nodes::{empty_image, extend_image_to_bounds};
@@ -295,10 +295,12 @@ fn brush(
_ => BlendMode::Restore, _ => BlendMode::Restore,
}; };
erase_restore_mask = blit(&(), List::new_from_item(erase_restore_mask), brush_texture, positions, move |a, b| blend_colors(a, b, mask_blend_mode, 1.)) erase_restore_mask = blit(&(), List::new_from_item(erase_restore_mask), brush_texture, positions, move |a, b| {
.into_iter() blend_colors(a, b, mask_blend_mode, 1.)
.next() })
.unwrap_or_default(); .into_iter()
.next()
.unwrap_or_default();
} }
actual_image = blend_image_closure(erase_restore_mask, actual_image, |a, b| blend_colors(a, b, BlendMode::MultiplyAlpha, 1.)); actual_image = blend_image_closure(erase_restore_mask, actual_image, |a, b| blend_colors(a, b, BlendMode::MultiplyAlpha, 1.));
@@ -1,10 +1,10 @@
use core::f64; use core::f64;
use core_types::Color;
use core_types::context::{Context, ContextModification, Ctx, DeriveCtx}; use core_types::context::{Context, ContextModification, Ctx, DeriveCtx};
use core_types::gpoll::GPoll; use core_types::gpoll::GPoll;
use core_types::list::{AttributeDyn, AttributeValueDyn, List, ListDyn}; use core_types::list::{AttributeDyn, AttributeValueDyn, List, ListDyn};
use core_types::transform::Footprint; use core_types::transform::Footprint;
use core_types::uuid::NodeId; use core_types::uuid::NodeId;
use core_types::Color;
use glam::{DAffine2, DVec2}; use glam::{DAffine2, DVec2};
use graphic_types::vector_types::GradientStops; use graphic_types::vector_types::GradientStops;
use graphic_types::{Artboard, Graphic, Vector}; use graphic_types::{Artboard, Graphic, Vector};
@@ -3,15 +3,15 @@ use base64::Engine;
#[cfg(target_family = "wasm")] #[cfg(target_family = "wasm")]
use canvas_utils::{Canvas, CanvasHandle}; use canvas_utils::{Canvas, CanvasHandle};
use core_types::color::SRGBA8; use core_types::color::SRGBA8;
use core_types::gpoll::GPoll;
use core_types::list::{Item, List}; use core_types::list::{Item, List};
#[cfg(target_family = "wasm")] #[cfg(target_family = "wasm")]
use core_types::math::bbox::Bbox; use core_types::math::bbox::Bbox;
use core_types::runtime::SourceFuture;
#[cfg(target_family = "wasm")] #[cfg(target_family = "wasm")]
use core_types::transform::Footprint; use core_types::transform::Footprint;
#[cfg(target_family = "wasm")] #[cfg(target_family = "wasm")]
use core_types::{ATTR_EDITOR_MERGED_LAYERS, ATTR_TRANSFORM, WasmNotSend}; use core_types::{ATTR_EDITOR_MERGED_LAYERS, ATTR_TRANSFORM, WasmNotSend};
use core_types::gpoll::GPoll;
use core_types::runtime::SourceFuture;
use core_types::{Color, Ctx}; use core_types::{Color, Ctx};
pub use graph_craft::application_io::resource::{Resource, ResourceHash}; pub use graph_craft::application_io::resource::{Resource, ResourceHash};
pub use graph_craft::application_io::*; pub use graph_craft::application_io::*;
@@ -12,11 +12,7 @@ use wgpu::util::DeviceExt;
use wgpu_executor::{WgpuExecutor, WgpuPipeline, WgpuPipelineCache}; use wgpu_executor::{WgpuExecutor, WgpuPipeline, WgpuPipelineCache};
#[node_macro::node(category(""))] #[node_macro::node(category(""))]
fn render_background<'a>( fn render_background<'a>(ctx: impl Ctx + ExtractFootprint + ExtractVarArgs, #[scope(composite_background_pipeline::IDENTIFIER)] pipeline: WgpuPipelineCache, data: RenderOutput) -> RenderOutput {
ctx: impl Ctx + ExtractFootprint + ExtractVarArgs,
#[scope(composite_background_pipeline::IDENTIFIER)] pipeline: WgpuPipelineCache,
data: RenderOutput,
) -> RenderOutput {
let footprint = ctx.footprint(); let footprint = ctx.footprint();
let render_params = ctx let render_params = ctx
.vararg(0) .vararg(0)
+13 -2
View File
@@ -209,7 +209,11 @@ mod tests {
assert_eq!(ctx.try_animation_time(), Some(2.0)); assert_eq!(ctx.try_animation_time(), Some(2.0));
assert_eq!(ctx.try_pointer_position(), Some(glam::DVec2::new(3.0, 4.0))); assert_eq!(ctx.try_pointer_position(), Some(glam::DVec2::new(3.0, 4.0)));
GPoll::Final(RenderOutput { GPoll::Final(RenderOutput {
data: RenderOutputType::Buffer { data: Vec::new(), width: 0, height: 0 }, data: RenderOutputType::Buffer {
data: Vec::new(),
width: 0,
height: 0,
},
metadata: RenderMetadata::default(), metadata: RenderMetadata::default(),
}) })
} }
@@ -240,6 +244,13 @@ mod tests {
let GPoll::Final(result) = <CreateContextNode<ProbeNode> as GNode<ContextImpl>>::eval(&graph, &ctx) else { let GPoll::Final(result) = <CreateContextNode<ProbeNode> as GNode<ContextImpl>>::eval(&graph, &ctx) else {
panic!("create_context must complete synchronously"); panic!("create_context must complete synchronously");
}; };
assert_eq!(result.data, RenderOutputType::Buffer { data: Vec::new(), width: 0, height: 0 }); assert_eq!(
result.data,
RenderOutputType::Buffer {
data: Vec::new(),
width: 0,
height: 0
}
);
} }
} }
+5 -5
View File
@@ -3,11 +3,11 @@ use core::f64::consts::{PI, TAU};
use core::hash::{Hash, Hasher}; use core::hash::{Hash, Hasher};
use core_types::blending::BlendMode; use core_types::blending::BlendMode;
use core_types::bounds::{BoundingBox, RenderBoundingBox}; use core_types::bounds::{BoundingBox, RenderBoundingBox};
use core_types::gpoll::Interrupt;
use core_types::list::{ATTR_FILL, ATTR_STROKE, Item, ItemAttributeValues, List, ListDyn}; use core_types::list::{ATTR_FILL, ATTR_STROKE, Item, ItemAttributeValues, List, ListDyn};
use core_types::registry::types::{Angle, Length, Multiplier, Percentage, PixelLength, Progression, SeedValue}; use core_types::registry::types::{Angle, Length, Multiplier, Percentage, PixelLength, Progression, SeedValue};
use core_types::transform::{Footprint, Transform}; use core_types::transform::{Footprint, Transform};
use core_types::uuid::NodeId; use core_types::uuid::NodeId;
use core_types::gpoll::Interrupt;
use core_types::{ use core_types::{
ATTR_BLEND_MODE, ATTR_CLIPPING_MASK, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_GRADIENT_TYPE, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_SPREAD_METHOD, ATTR_TRANSFORM, Color, Context, ATTR_BLEND_MODE, ATTR_CLIPPING_MASK, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_GRADIENT_TYPE, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_SPREAD_METHOD, ATTR_TRANSFORM, Color, Context,
Ctx, DeriveCtx, Ctx, DeriveCtx,
@@ -116,7 +116,7 @@ fn assign_colors<T>(
repeat_every: u32, repeat_every: u32,
) -> T ) -> T
where where
T: VectorListIterMut+ Send, T: VectorListIterMut + Send,
{ {
let Some(row) = gradient.into_iter().next() else { return content }; let Some(row) = gradient.into_iter().next() else { return content };
@@ -157,7 +157,7 @@ where
/// Applies a fill style to the vector content, giving an appearance to the area within the interior of the geometry. /// Applies a fill style to the vector content, giving an appearance to the area within the interior of the geometry.
#[node_macro::node(category("Vector: Style"), path(graphene_core::vector), properties("fill_properties"))] #[node_macro::node(category("Vector: Style"), path(graphene_core::vector), properties("fill_properties"))]
fn fill<V: VectorListIterMut+ Send, F: IntoGraphicList+ Send + 'static>( fn fill<V: VectorListIterMut + Send, F: IntoGraphicList + Send + 'static>(
_: impl Ctx, _: impl Ctx,
/// The content with vector paths to apply the fill style to. /// The content with vector paths to apply the fill style to.
#[implementations( #[implementations(
@@ -252,7 +252,7 @@ impl IntoF64Vec for String {
/// Applies a stroke style to the vector content, giving an appearance to the area within the outline of the geometry. /// Applies a stroke style to the vector content, giving an appearance to the area within the outline of the geometry.
#[node_macro::node(category("Vector: Style"), path(graphene_core::vector), properties("stroke_properties"))] #[node_macro::node(category("Vector: Style"), path(graphene_core::vector), properties("stroke_properties"))]
fn stroke<V, L: IntoF64Vec, P: IntoGraphicList+ Send + 'static>( fn stroke<V, L: IntoF64Vec, P: IntoGraphicList + Send + 'static>(
_: impl Ctx, _: impl Ctx,
/// The content with vector paths to apply the stroke style to. /// The content with vector paths to apply the stroke style to.
#[implementations( #[implementations(
@@ -324,7 +324,7 @@ fn stroke<V, L: IntoF64Vec, P: IntoGraphicList+ Send + 'static>(
dash_offset: f64, dash_offset: f64,
) -> List<V> ) -> List<V>
where where
List<V>: VectorListIterMut+ Send, List<V>: VectorListIterMut + Send,
{ {
let dash_lengths = dash_lengths.into_vec().into_iter().map(|length| length.max(0.)).collect(); let dash_lengths = dash_lengths.into_vec().into_iter().map(|length| length.max(0.)).collect();