From fcf5b2f8020473fb600a989e5000be04902ed0ae Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Thu, 19 Jun 2025 10:10:43 +0530 Subject: [PATCH 01/11] Add masking --- .../node_graph/document_node_definitions.rs | 2 +- node-graph/gcore/src/graphic_element.rs | 7 ++++ .../gcore/src/graphic_element/renderer.rs | 35 ++++++++++++++++++ node-graph/gcore/src/instances.rs | 36 ++++++++++++++++--- node-graph/gcore/src/raster/image.rs | 2 ++ node-graph/gcore/src/vector/vector_nodes.rs | 4 +++ node-graph/gstd/src/raster.rs | 32 ++++++++++++++--- node-graph/gstd/src/vector.rs | 1 + 8 files changed, 109 insertions(+), 10 deletions(-) diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs index 239e4e894e..e926bf3fb1 100644 --- a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs +++ b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs @@ -16,7 +16,7 @@ use graph_craft::document::value::*; use graph_craft::document::*; use graphene_std::ops::XY; use graphene_std::raster::brush_cache::BrushCache; -use graphene_std::raster::{CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, NoiseType, RedGreenBlueAlpha}; +use graphene_std::raster::{CellularDistanceFunction, CellularReturnType, DomainWarpType, FractalType, NoiseType, RedGreenBlueAlpha}; use graphene_std::raster_types::{CPU, RasterDataTable}; use graphene_std::text::{Font, TypesettingConfig}; use graphene_std::transform::Footprint; diff --git a/node-graph/gcore/src/graphic_element.rs b/node-graph/gcore/src/graphic_element.rs index 4f21cdfc0c..7b4fd6e067 100644 --- a/node-graph/gcore/src/graphic_element.rs +++ b/node-graph/gcore/src/graphic_element.rs @@ -101,6 +101,7 @@ pub fn migrate_graphic_group<'de, D: serde::Deserializer<'de>>(deserializer: D) for (graphic_element, source_node_id) in old.elements { graphic_group_table.push(Instance { instance: graphic_element, + mask: None, transform: old.transform, alpha_blending: old.alpha_blending, source_node_id, @@ -116,6 +117,7 @@ pub fn migrate_graphic_group<'de, D: serde::Deserializer<'de>>(deserializer: D) for (graphic_element, source_node_id) in &instance.instance.elements { graphic_group_table.push(Instance { instance: graphic_element.clone(), + mask: None, transform: *instance.transform, alpha_blending: *instance.alpha_blending, source_node_id: *source_node_id, @@ -332,6 +334,7 @@ pub fn migrate_artboard_group<'de, D: serde::Deserializer<'de>>(deserializer: D) for (artboard, source_node_id) in artboard_group.artboards { table.push(Instance { instance: artboard, + mask: None, transform: DAffine2::IDENTITY, alpha_blending: AlphaBlending::default(), source_node_id, @@ -352,6 +355,7 @@ async fn layer(_: impl Ctx, mut stack: GraphicGroupTable, element: GraphicElemen stack.push(Instance { instance: element, + mask: None, transform: DAffine2::IDENTITY, alpha_blending: AlphaBlending::default(), source_node_id, @@ -412,6 +416,7 @@ async fn flatten_group(_: impl Ctx, group: GraphicGroupTable, fully_flatten: boo _ => { output_group_table.push(Instance { instance: current_element, + mask: None, transform: *current_instance.transform, alpha_blending: *current_instance.alpha_blending, source_node_id: reference, @@ -450,6 +455,7 @@ async fn flatten_vector(_: impl Ctx, group: GraphicGroupTable) -> VectorDataTabl for current_element in vector_instance.instance_ref_iter() { output_group_table.push(Instance { instance: current_element.instance.clone(), + mask: None, transform: *current_instance.transform * *current_element.transform, alpha_blending: AlphaBlending { blend_mode: current_element.alpha_blending.blend_mode, @@ -514,6 +520,7 @@ async fn append_artboard(_ctx: impl Ctx, mut artboards: ArtboardGroupTable, artb artboards.push(Instance { instance: artboard, + mask: None, transform: DAffine2::IDENTITY, alpha_blending: AlphaBlending::default(), source_node_id: encapsulating_node_id, diff --git a/node-graph/gcore/src/graphic_element/renderer.rs b/node-graph/gcore/src/graphic_element/renderer.rs index 52c007ac6c..fc49b1c6f8 100644 --- a/node-graph/gcore/src/graphic_element/renderer.rs +++ b/node-graph/gcore/src/graphic_element/renderer.rs @@ -432,6 +432,20 @@ impl GraphicElementRendered for GraphicGroupTable { attributes.push(mask_type.to_attribute(), selector); } + + if let Some(mask) = instance.mask { + let uuid = generate_uuid(); + let mask_type = if mask.can_reduce_to_clip_path() { MaskType::Clip } else { MaskType::Mask }; + let mut svg = SvgRender::new(); + mask.render_svg(&mut svg, &render_params.for_clipper()); + + write!(&mut attributes.0.svg_defs, r##"{}"##, svg.svg_defs).unwrap(); + mask_type.write_to_defs(&mut attributes.0.svg_defs, uuid, svg.svg.to_svg_string()); + let id = format!("mask-{}", uuid); + let selector = format!("url(#{id})"); + + attributes.push(mask_type.to_attribute(), selector); + } }, |render| { instance.instance.render_svg(render, render_params); @@ -474,6 +488,20 @@ impl GraphicElementRendered for GraphicGroupTable { } } + let mut masked = false; + if let Some(mask) = instance.mask { + let bounds = mask.bounding_box(transform, true); + + if let Some(bounds) = bounds { + masked = true; + let rect = vello::kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y); + + scene.push_layer(peniko::Mix::Normal, 1., kurbo::Affine::IDENTITY, &rect); + mask.render_to_vello(scene, transform, context, &render_params.for_clipper()); + scene.push_layer(peniko::BlendMode::new(peniko::Mix::Clip, peniko::Compose::SrcIn), 1., kurbo::Affine::IDENTITY, &rect); + } + } + let next_clips = iter.peek().is_some_and(|next_instance| next_instance.instance.had_clip_enabled()); if next_clips && mask_instance_state.is_none() { mask_instance_state = Some((instance.instance, transform)); @@ -502,6 +530,11 @@ impl GraphicElementRendered for GraphicGroupTable { instance.instance.render_to_vello(scene, transform, context, render_params); } + if masked { + scene.pop_layer(); + scene.pop_layer(); + } + if layer { scene.pop_layer(); } @@ -614,6 +647,7 @@ impl GraphicElementRendered for VectorDataTable { vector_row.push(Instance { instance: fill_instance, + mask: None, alpha_blending: *instance.alpha_blending, transform: *instance.transform, source_node_id: None, @@ -734,6 +768,7 @@ impl GraphicElementRendered for VectorDataTable { vector_data.push(Instance { instance: fill_instance, + mask: None, alpha_blending: *instance.alpha_blending, transform: *instance.transform, source_node_id: None, diff --git a/node-graph/gcore/src/instances.rs b/node-graph/gcore/src/instances.rs index 6a6918c713..5063cd61be 100644 --- a/node-graph/gcore/src/instances.rs +++ b/node-graph/gcore/src/instances.rs @@ -1,13 +1,17 @@ -use crate::AlphaBlending; +use crate::{AlphaBlending, GraphicElement}; use crate::uuid::NodeId; use dyn_any::StaticType; use glam::DAffine2; use std::hash::Hash; +pub type Mask = Option; + #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] pub struct Instances { #[serde(alias = "instances")] instance: Vec, + #[serde(default = "one_mask_default")] + mask: Vec, #[serde(default = "one_daffine2_default")] transform: Vec, #[serde(default = "one_alpha_blending_default")] @@ -20,6 +24,7 @@ impl Instances { pub fn new(instance: T) -> Self { Self { instance: vec![instance], + mask: vec![None], transform: vec![DAffine2::IDENTITY], alpha_blending: vec![AlphaBlending::default()], source_node_id: vec![None], @@ -28,6 +33,7 @@ impl Instances { pub fn push(&mut self, instance: Instance) { self.instance.push(instance.instance); + self.mask.push(instance.mask); self.transform.push(instance.transform); self.alpha_blending.push(instance.alpha_blending); self.source_node_id.push(instance.source_node_id); @@ -43,11 +49,13 @@ impl Instances { pub fn instance_iter(self) -> impl DoubleEndedIterator> { self.instance .into_iter() + .zip(self.mask) .zip(self.transform) .zip(self.alpha_blending) .zip(self.source_node_id) - .map(|(((instance, transform), alpha_blending), source_node_id)| Instance { + .map(|((((instance, mask), transform), alpha_blending), source_node_id)| Instance { instance, + mask, transform, alpha_blending, source_node_id, @@ -57,11 +65,13 @@ impl Instances { pub fn instance_ref_iter(&self) -> impl DoubleEndedIterator> + Clone { self.instance .iter() + .zip(self.mask.iter()) .zip(self.transform.iter()) .zip(self.alpha_blending.iter()) .zip(self.source_node_id.iter()) - .map(|(((instance, transform), alpha_blending), source_node_id)| InstanceRef { + .map(|((((instance, mask), transform), alpha_blending), source_node_id)| InstanceRef { instance, + mask, transform, alpha_blending, source_node_id, @@ -71,11 +81,13 @@ impl Instances { pub fn instance_mut_iter(&mut self) -> impl DoubleEndedIterator> { self.instance .iter_mut() + .zip(self.mask.iter_mut()) .zip(self.transform.iter_mut()) .zip(self.alpha_blending.iter_mut()) .zip(self.source_node_id.iter_mut()) - .map(|(((instance, transform), alpha_blending), source_node_id)| InstanceMut { + .map(|((((instance, mask), transform), alpha_blending), source_node_id)| InstanceMut { instance, + mask, transform, alpha_blending, source_node_id, @@ -89,6 +101,7 @@ impl Instances { Some(InstanceRef { instance: &self.instance[index], + mask: &self.mask[index], transform: &self.transform[index], alpha_blending: &self.alpha_blending[index], source_node_id: &self.source_node_id[index], @@ -102,6 +115,7 @@ impl Instances { Some(InstanceMut { instance: &mut self.instance[index], + mask: &mut self.mask[index], transform: &mut self.transform[index], alpha_blending: &mut self.alpha_blending[index], source_node_id: &mut self.source_node_id[index], @@ -121,6 +135,7 @@ impl Default for Instances { fn default() -> Self { Self { instance: Vec::new(), + mask: Vec::new(), transform: Vec::new(), alpha_blending: Vec::new(), source_node_id: Vec::new(), @@ -146,6 +161,9 @@ unsafe impl StaticType for Instances { type Static = Instances; } +fn one_mask_default() -> Vec { + vec![None] +} fn one_daffine2_default() -> Vec { vec![DAffine2::IDENTITY] } @@ -159,6 +177,7 @@ fn one_source_node_id_default() -> Vec> { #[derive(Copy, Clone, Debug, PartialEq)] pub struct InstanceRef<'a, T> { pub instance: &'a T, + pub mask: &'a Mask, pub transform: &'a DAffine2, pub alpha_blending: &'a AlphaBlending, pub source_node_id: &'a Option, @@ -171,6 +190,7 @@ impl InstanceRef<'_, T> { { Instance { instance: self.instance.clone(), + mask: self.mask.clone(), transform: *self.transform, alpha_blending: *self.alpha_blending, source_node_id: *self.source_node_id, @@ -181,14 +201,16 @@ impl InstanceRef<'_, T> { #[derive(Debug)] pub struct InstanceMut<'a, T> { pub instance: &'a mut T, + pub mask: &'a mut Mask, pub transform: &'a mut DAffine2, pub alpha_blending: &'a mut AlphaBlending, pub source_node_id: &'a mut Option, } -#[derive(Copy, Clone, Default, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +#[derive(Clone, Default, Debug, PartialEq, serde::Serialize, serde::Deserialize)] pub struct Instance { pub instance: T, + pub mask: Mask, pub transform: DAffine2, pub alpha_blending: AlphaBlending, pub source_node_id: Option, @@ -201,6 +223,7 @@ impl Instance { { Instance { instance: self.instance.into(), + mask: self.mask, transform: self.transform, alpha_blending: self.alpha_blending, source_node_id: self.source_node_id, @@ -210,6 +233,7 @@ impl Instance { pub fn to_instance_ref(&self) -> InstanceRef { InstanceRef { instance: &self.instance, + mask: &self.mask, transform: &self.transform, alpha_blending: &self.alpha_blending, source_node_id: &self.source_node_id, @@ -219,6 +243,7 @@ impl Instance { pub fn to_instance_mut(&mut self) -> InstanceMut { InstanceMut { instance: &mut self.instance, + mask: &mut self.mask, transform: &mut self.transform, alpha_blending: &mut self.alpha_blending, source_node_id: &mut self.source_node_id, @@ -228,6 +253,7 @@ impl Instance { pub fn to_table(self) -> Instances { Instances { instance: vec![self.instance], + mask: vec![self.mask], transform: vec![self.transform], alpha_blending: vec![self.alpha_blending], source_node_id: vec![self.source_node_id], diff --git a/node-graph/gcore/src/raster/image.rs b/node-graph/gcore/src/raster/image.rs index 36254461ad..4f8c8d56d0 100644 --- a/node-graph/gcore/src/raster/image.rs +++ b/node-graph/gcore/src/raster/image.rs @@ -393,6 +393,7 @@ pub fn migrate_image_frame_instance<'de, D: serde::Deserializer<'de>>(deserializ }, FormatVersions::OldImageFrame(image_frame_with_transform_and_blending) => Instance { instance: Raster::new_cpu(image_frame_with_transform_and_blending.image), + mask: None, transform: image_frame_with_transform_and_blending.transform, alpha_blending: image_frame_with_transform_and_blending.alpha_blending, source_node_id: None, @@ -461,6 +462,7 @@ impl From> for Image { // for image_frame_instance in image_frame_table.instance_iter() { // result_table.push(Instance { // instance: image_frame_instance.instance, +// mask: image_frame_instance.mask, // transform: image_frame_instance.transform, // alpha_blending: image_frame_instance.alpha_blending, // source_node_id: image_frame_instance.source_node_id, diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index 79d768ff15..e8c30f2d68 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -448,6 +448,7 @@ async fn round_corners( for source in source.instance_ref_iter() { let source_transform = *source.transform; let source_transform_inverse = source_transform.inverse(); + let source_mask = source.mask; let source = source.instance; let upstream_graphic_group = source.upstream_graphic_group.clone(); @@ -540,6 +541,7 @@ async fn round_corners( result_table.push(Instance { instance: result, + mask: source_mask.clone(), transform: source_transform, alpha_blending: Default::default(), source_node_id: None, @@ -788,6 +790,7 @@ async fn auto_tangents( for source in source.instance_ref_iter() { let transform = *source.transform; + let mask = source.mask.clone(); let alpha_blending = *source.alpha_blending; let source_node_id = *source.source_node_id; let source = source.instance; @@ -886,6 +889,7 @@ async fn auto_tangents( result_table.push(Instance { instance: result, + mask, transform, alpha_blending, source_node_id, diff --git a/node-graph/gstd/src/raster.rs b/node-graph/gstd/src/raster.rs index 55f2792ce1..00941bf9bc 100644 --- a/node-graph/gstd/src/raster.rs +++ b/node-graph/gstd/src/raster.rs @@ -1,3 +1,4 @@ +use crate::instances::Instances; use dyn_any::DynAny; use fastnoise_lite; use glam::{DAffine2, DVec2, Vec2}; @@ -6,7 +7,9 @@ use graphene_core::raster::bbox::Bbox; pub use graphene_core::raster::*; use graphene_core::raster_types::{CPU, Raster, RasterDataTable}; use graphene_core::transform::Transform; +use graphene_core::vector::VectorDataTable; use graphene_core::{AlphaBlending, Ctx, ExtractFootprint}; +use graphene_core::{GraphicElement, GraphicGroupTable}; use rand::prelude::*; use rand_chacha::ChaCha8Rng; use std::fmt::Debug; @@ -171,6 +174,7 @@ fn combine_channels( // Add this instance to the result table result_table.push(Instance { instance: Raster::new_cpu(image), + mask: None, transform, alpha_blending, source_node_id: None, @@ -181,14 +185,34 @@ fn combine_channels( } #[node_macro::node(category("Raster"))] -fn mask( +fn mask( _: impl Ctx, /// The image to be masked. - image: RasterDataTable, + #[implementations( + VectorDataTable, + RasterDataTable, + GraphicGroupTable + )] + mut image: Instances, /// The stencil to be used for masking. #[expose] - stencil: RasterDataTable, -) -> RasterDataTable { + #[implementations( + VectorDataTable, + RasterDataTable, + GraphicGroupTable + )] + stencil: Instances, +) -> Instances +where + Instances: Into + Clone, +{ + for instance in image.instance_mut_iter() { + *instance.mask = Some(stencil.clone().into()); + } + image +} + +fn mask_lambda(image: RasterDataTable, stencil: RasterDataTable) -> RasterDataTable { // TODO: Support multiple stencil instances let Some(stencil_instance) = stencil.instance_iter().next() else { // No stencil provided so we return the original image diff --git a/node-graph/gstd/src/vector.rs b/node-graph/gstd/src/vector.rs index 4fbf3a664c..cbf4f48e0b 100644 --- a/node-graph/gstd/src/vector.rs +++ b/node-graph/gstd/src/vector.rs @@ -178,6 +178,7 @@ fn difference<'a>(vector_data: impl DoubleEndedIterator Date: Wed, 9 Jul 2025 07:36:43 +0530 Subject: [PATCH 02/11] add: mask to spreadsheet viewer --- .../portfolio/spreadsheet/spreadsheet_message_handler.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs b/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs index 378c8b1b52..5e28d514b1 100644 --- a/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs +++ b/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs @@ -299,6 +299,8 @@ impl InstanceLayout for Instances { TextButton::new(instance.instance.identifier()) .on_update(move |_| SpreadsheetMessage::PushToInstancePath { index }.into()) .widget_holder(), + // Add the mask information here. We'll simply display "Yes" or "No". + TextLabel::new(if instance.mask.is_some() { "Yes" } else { "No" }.to_string()).widget_holder(), TextLabel::new(format!( "Location: ({} px, {} px) — Rotation: {rotation:2}° — Scale: ({}x, {}x)", round(translation.x), @@ -313,7 +315,8 @@ impl InstanceLayout for Instances { }) .collect::>(); - rows.insert(0, column_headings(&["", "instance", "transform", "alpha_blending", "source_node_id"])); + // Add "mask" to the column headings + rows.insert(0, column_headings(&["", "instance", "mask", "transform", "alpha_blending", "source_node_id"])); let instances = vec![TextLabel::new("Instances:").widget_holder()]; vec![LayoutGroup::Row { widgets: instances }, LayoutGroup::Table { rows }] From 9c0847f3fda48e47ca8b85a3f79107f0bf38ea8c Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 9 Jul 2025 19:20:10 +0530 Subject: [PATCH 03/11] add: masking to vector data --- node-graph/gsvg-renderer/src/renderer.rs | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/node-graph/gsvg-renderer/src/renderer.rs b/node-graph/gsvg-renderer/src/renderer.rs index 43d7acaed9..fc26fe3c1a 100644 --- a/node-graph/gsvg-renderer/src/renderer.rs +++ b/node-graph/gsvg-renderer/src/renderer.rs @@ -531,6 +531,21 @@ impl GraphicElementRendered for VectorDataTable { let selector = format!("url(#{id})"); attributes.push(mask_type.to_attribute(), selector); } + + if let Some(mask) = instance.mask { + let uuid = generate_uuid(); + let mask_type = if mask.can_reduce_to_clip_path() { MaskType::Clip } else { MaskType::Mask }; + let mut svg = SvgRender::new(); + mask.render_svg(&mut svg, &render_params.for_clipper()); + + write!(&mut attributes.0.svg_defs, r##"{}"##, svg.svg_defs).unwrap(); + mask_type.write_to_defs(&mut attributes.0.svg_defs, uuid, svg.svg.to_svg_string()); + let id = format!("mask-{}", uuid); + let selector = format!("url(#{id})"); + + attributes.push(mask_type.to_attribute(), selector); + } + attributes.push_val(fill_and_stroke); let factor = if render_params.for_mask { 1. } else { instance.alpha_blending.fill }; @@ -587,6 +602,22 @@ impl GraphicElementRendered for VectorDataTable { ); } + + let mut masked = false; + if let Some(mask) = instance.mask { + let transform = applied_stroke_transform; + let bounds = mask.bounding_box(transform, true); + + if let Some(bounds) = bounds { + masked = true; + let rect = vello::kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y); + + scene.push_layer(peniko::Mix::Normal, 1., kurbo::Affine::IDENTITY, &rect); + mask.render_to_vello(scene, transform, _context, &render_params.for_clipper()); + scene.push_layer(peniko::BlendMode::new(peniko::Mix::Clip, peniko::Compose::SrcIn), 1., kurbo::Affine::IDENTITY, &rect); + } + } + let can_draw_aligned_stroke = instance.instance.style.stroke().is_some_and(|stroke| stroke.has_renderable_stroke() && stroke.align.is_not_centered()) && instance.instance.stroke_bezier_paths().all(|path| path.closed()); @@ -748,6 +779,11 @@ impl GraphicElementRendered for VectorDataTable { scene.pop_layer(); } + if masked { + scene.pop_layer(); + scene.pop_layer(); + } + // If we pushed a layer for opacity or a blend mode, we need to pop it if layer { scene.pop_layer(); From 13a48079406b5f27669e6ddcb90469fca70b3075 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 9 Jul 2025 19:55:24 +0530 Subject: [PATCH 04/11] fix: vello vector data --- node-graph/graster-nodes/src/std_nodes.rs | 12 +++++++ node-graph/gsvg-renderer/src/renderer.rs | 41 ++++++++++++++++++++--- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/node-graph/graster-nodes/src/std_nodes.rs b/node-graph/graster-nodes/src/std_nodes.rs index 7ba8e15cd1..fb1ae6d726 100644 --- a/node-graph/graster-nodes/src/std_nodes.rs +++ b/node-graph/graster-nodes/src/std_nodes.rs @@ -195,13 +195,25 @@ pub fn mask( /// The image to be masked. #[implementations( VectorDataTable, + VectorDataTable, + VectorDataTable, + RasterDataTable, + RasterDataTable, RasterDataTable, + GraphicGroupTable, + GraphicGroupTable, GraphicGroupTable )] mut image: Instances, /// The stencil to be used for masking. #[expose] #[implementations( + VectorDataTable, + RasterDataTable, + GraphicGroupTable, + VectorDataTable, + RasterDataTable, + GraphicGroupTable, VectorDataTable, RasterDataTable, GraphicGroupTable diff --git a/node-graph/gsvg-renderer/src/renderer.rs b/node-graph/gsvg-renderer/src/renderer.rs index fc26fe3c1a..a031746547 100644 --- a/node-graph/gsvg-renderer/src/renderer.rs +++ b/node-graph/gsvg-renderer/src/renderer.rs @@ -602,18 +602,16 @@ impl GraphicElementRendered for VectorDataTable { ); } - let mut masked = false; if let Some(mask) = instance.mask { - let transform = applied_stroke_transform; - let bounds = mask.bounding_box(transform, true); + let bounds = mask.bounding_box(element_transform, true); if let Some(bounds) = bounds { masked = true; let rect = vello::kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y); scene.push_layer(peniko::Mix::Normal, 1., kurbo::Affine::IDENTITY, &rect); - mask.render_to_vello(scene, transform, _context, &render_params.for_clipper()); + mask.render_to_vello(scene, element_transform, _context, &render_params.for_clipper()); scene.push_layer(peniko::BlendMode::new(peniko::Mix::Clip, peniko::Compose::SrcIn), 1., kurbo::Affine::IDENTITY, &rect); } } @@ -1039,12 +1037,26 @@ impl GraphicElementRendered for RasterDataTable { if instance.alpha_blending.blend_mode != BlendMode::default() { attributes.push("style", instance.alpha_blending.blend_mode.render()); } + + if let Some(mask) = instance.mask { + let uuid = generate_uuid(); + let mask_type = if mask.can_reduce_to_clip_path() { MaskType::Clip } else { MaskType::Mask }; + let mut svg = SvgRender::new(); + mask.render_svg(&mut svg, &render_params.for_clipper()); + + write!(&mut attributes.0.svg_defs, r##"{}"##, svg.svg_defs).unwrap(); + mask_type.write_to_defs(&mut attributes.0.svg_defs, uuid, svg.svg.to_svg_string()); + let id = format!("mask-{}", uuid); + let selector = format!("url(#{id})"); + + attributes.push(mask_type.to_attribute(), selector); + } }); } } #[cfg(feature = "vello")] - fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, _: &mut RenderContext, _render_params: &RenderParams) { + fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, _context: &mut RenderContext, render_params: &RenderParams) { use vello::peniko; for instance in self.instance_ref_iter() { @@ -1055,7 +1067,26 @@ impl GraphicElementRendered for RasterDataTable { let image = peniko::Image::new(image.to_flat_u8().0.into(), peniko::Format::Rgba8, image.width, image.height).with_extend(peniko::Extend::Repeat); let transform = transform * *instance.transform * DAffine2::from_scale(1. / DVec2::new(image.width as f64, image.height as f64)); + let mut masked = false; + if let Some(mask) = instance.mask { + let bounds = mask.bounding_box(transform, true); + + if let Some(bounds) = bounds { + masked = true; + let rect = vello::kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y); + + scene.push_layer(peniko::Mix::Normal, 1., kurbo::Affine::IDENTITY, &rect); + mask.render_to_vello(scene, transform, _context, &render_params.for_clipper()); + scene.push_layer(peniko::BlendMode::new(peniko::Mix::Clip, peniko::Compose::SrcIn), 1., kurbo::Affine::IDENTITY, &rect); + } + } + scene.draw_image(&image, kurbo::Affine::new(transform.to_cols_array())); + + if masked { + scene.pop_layer(); + scene.pop_layer(); + } } } From 9c367aea6cef2e0bf7585327318d708d130737a2 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Wed, 9 Jul 2025 19:19:11 -0700 Subject: [PATCH 05/11] Update website deployment CI script to output auto-generated code docs artifacts --- .github/workflows/website.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index 0451d4226e..93bda7e01d 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -9,6 +9,7 @@ on: pull_request: paths: - website/** + workflow_dispatch: {} env: CARGO_TERM_COLOR: always INDEX_HTML_HEAD_INCLUSION: @@ -80,8 +81,32 @@ jobs: - name: 🚚 Move `website/other/dist` contents to `website/public` run: | + mkdir -p website/public mv website/other/dist/* website/public + - name: 💿 Obtain cache of auto-generated code docs artifacts + id: cache-website-code-docs + uses: actions/cache/restore@v3 + with: + path: artifacts + key: website-code-docs + + - name: 📁 Fallback in case auto-generated code docs artifacts weren't cached + if: steps.cache-website-code-docs.outputs.cache-hit != 'true' + run: | + echo "🦀 Initial system version of Rust:" + rustc --version + rustup update stable + echo "🦀 Latest updated version of Rust:" + rustc --version + cargo test --package graphite-editor --lib -- messages::message::test::generate_message_tree + mkdir artifacts + mv hierarchical_message_system_tree.txt artifacts/hierarchical_message_system_tree.txt + + - name: 🚚 Move `artifacts` contents to `website/public` + run: | + mv artifacts/* website/public + - name: 📤 Publish to Cloudflare Pages id: cloudflare uses: cloudflare/pages-action@1 From a022d654d2d610298948f44acd42a9b6b69fd1c0 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Thu, 10 Jul 2025 13:22:30 +0530 Subject: [PATCH 06/11] cargo: fmt --- node-graph/gcore/src/instances.rs | 2 +- node-graph/graster-nodes/src/std_nodes.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/node-graph/gcore/src/instances.rs b/node-graph/gcore/src/instances.rs index 9a79228ed1..dcafa83f42 100644 --- a/node-graph/gcore/src/instances.rs +++ b/node-graph/gcore/src/instances.rs @@ -1,5 +1,5 @@ -use crate::{AlphaBlending, GraphicElement}; use crate::uuid::NodeId; +use crate::{AlphaBlending, GraphicElement}; use dyn_any::StaticType; use glam::DAffine2; use std::hash::Hash; diff --git a/node-graph/graster-nodes/src/std_nodes.rs b/node-graph/graster-nodes/src/std_nodes.rs index fb1ae6d726..3798955d57 100644 --- a/node-graph/graster-nodes/src/std_nodes.rs +++ b/node-graph/graster-nodes/src/std_nodes.rs @@ -1,4 +1,3 @@ -use graphene_core::instances::Instances; use crate::adjustments::{CellularDistanceFunction, CellularReturnType, DomainWarpType, FractalType, NoiseType}; use dyn_any::DynAny; use fastnoise_lite; @@ -8,6 +7,7 @@ use graphene_core::color::Color; use graphene_core::color::{Alpha, AlphaMut, Channel, LinearChannel, Luminance, RGBMut}; use graphene_core::context::{Ctx, ExtractFootprint}; use graphene_core::instances::Instance; +use graphene_core::instances::Instances; use graphene_core::math::bbox::Bbox; use graphene_core::raster::image::Image; use graphene_core::raster::{Bitmap, BitmapMut}; From 382b1e35d4c6da54735ff010e20cb36101860ef3 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sat, 12 Jul 2025 03:03:59 +0530 Subject: [PATCH 07/11] add: mask to raster data --- node-graph/gsvg-renderer/src/renderer.rs | 71 ++++++++++++++---------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/node-graph/gsvg-renderer/src/renderer.rs b/node-graph/gsvg-renderer/src/renderer.rs index 51ba0e19fd..55dd1e1cae 100644 --- a/node-graph/gsvg-renderer/src/renderer.rs +++ b/node-graph/gsvg-renderer/src/renderer.rs @@ -1021,38 +1021,51 @@ impl GraphicElementRendered for RasterDataTable { base64::engine::general_purpose::STANDARD.encode_string(output, &mut base64_string); base64_string }); - render.leaf_tag("image", |attributes| { - attributes.push("width", 1.to_string()); - attributes.push("height", 1.to_string()); - attributes.push("preserveAspectRatio", "none"); - attributes.push("href", base64_string); - let matrix = format_transform_matrix(transform); - if !matrix.is_empty() { - attributes.push("transform", matrix); - } - let factor = if render_params.for_mask { 1. } else { instance.alpha_blending.fill }; - let opacity = instance.alpha_blending.opacity * factor; - if opacity < 1. { - attributes.push("opacity", opacity.to_string()); - } - if instance.alpha_blending.blend_mode != BlendMode::default() { - attributes.push("style", instance.alpha_blending.blend_mode.render()); - } - if let Some(mask) = instance.mask { - let uuid = generate_uuid(); - let mask_type = if mask.can_reduce_to_clip_path() { MaskType::Clip } else { MaskType::Mask }; - let mut svg = SvgRender::new(); - mask.render_svg(&mut svg, &render_params.for_clipper()); + let render_image = |render: &mut SvgRender| { + render.leaf_tag("image", |attributes| { + attributes.push("width", 1.to_string()); + attributes.push("height", 1.to_string()); + attributes.push("preserveAspectRatio", "none"); + attributes.push("href", base64_string); + let matrix = format_transform_matrix(transform); + if !matrix.is_empty() { + attributes.push("transform", matrix); + } + let factor = if render_params.for_mask { 1. } else { instance.alpha_blending.fill }; + let opacity = instance.alpha_blending.opacity * factor; + if opacity < 1. { + attributes.push("opacity", opacity.to_string()); + } + if instance.alpha_blending.blend_mode != BlendMode::default() { + attributes.push("style", instance.alpha_blending.blend_mode.render()); + } + }) + }; - write!(&mut attributes.0.svg_defs, r##"{}"##, svg.svg_defs).unwrap(); - mask_type.write_to_defs(&mut attributes.0.svg_defs, uuid, svg.svg.to_svg_string()); - let id = format!("mask-{}", uuid); - let selector = format!("url(#{id})"); + // Unlike path and g elements, the mask attribute of image element is broken and + // behaves differently across different browsers. And so we use g to have it work correctly. + if let Some(mask) = instance.mask { + render.parent_tag( + "g", + |attributes| { + let uuid = generate_uuid(); + let mask_type = if mask.can_reduce_to_clip_path() { MaskType::Clip } else { MaskType::Mask }; + let mut svg = SvgRender::new(); + mask.render_svg(&mut svg, &render_params.for_clipper()); - attributes.push(mask_type.to_attribute(), selector); - } - }); + write!(&mut attributes.0.svg_defs, r##"{}"##, svg.svg_defs).unwrap(); + mask_type.write_to_defs(&mut attributes.0.svg_defs, uuid, svg.svg.to_svg_string()); + let id = format!("mask-{}", uuid); + let selector = format!("url(#{id})"); + + attributes.push(mask_type.to_attribute(), selector); + }, + render_image, + ); + } else { + render_image(render) + } } } From 89d6c970d4e945032db42d3bd84bf1b347c35776 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Sat, 12 Jul 2025 04:13:09 +0530 Subject: [PATCH 08/11] fix: replace alpha with luminance --- node-graph/gsvg-renderer/src/renderer.rs | 55 +++++++----------------- 1 file changed, 16 insertions(+), 39 deletions(-) diff --git a/node-graph/gsvg-renderer/src/renderer.rs b/node-graph/gsvg-renderer/src/renderer.rs index 55dd1e1cae..658813d487 100644 --- a/node-graph/gsvg-renderer/src/renderer.rs +++ b/node-graph/gsvg-renderer/src/renderer.rs @@ -273,17 +273,7 @@ impl GraphicElementRendered for GraphicGroupTable { } if let Some(mask) = instance.mask { - let uuid = generate_uuid(); - let mask_type = if mask.can_reduce_to_clip_path() { MaskType::Clip } else { MaskType::Mask }; - let mut svg = SvgRender::new(); - mask.render_svg(&mut svg, &render_params.for_clipper()); - - write!(&mut attributes.0.svg_defs, r##"{}"##, svg.svg_defs).unwrap(); - mask_type.write_to_defs(&mut attributes.0.svg_defs, uuid, svg.svg.to_svg_string()); - let id = format!("mask-{}", uuid); - let selector = format!("url(#{id})"); - - attributes.push(mask_type.to_attribute(), selector); + attributes.push_mask(mask, render_params.for_clipper()); } }, |render| { @@ -534,17 +524,7 @@ impl GraphicElementRendered for VectorDataTable { } if let Some(mask) = instance.mask { - let uuid = generate_uuid(); - let mask_type = if mask.can_reduce_to_clip_path() { MaskType::Clip } else { MaskType::Mask }; - let mut svg = SvgRender::new(); - mask.render_svg(&mut svg, &render_params.for_clipper()); - - write!(&mut attributes.0.svg_defs, r##"{}"##, svg.svg_defs).unwrap(); - mask_type.write_to_defs(&mut attributes.0.svg_defs, uuid, svg.svg.to_svg_string()); - let id = format!("mask-{}", uuid); - let selector = format!("url(#{id})"); - - attributes.push(mask_type.to_attribute(), selector); + attributes.push_mask(mask, render_params.for_clipper()); } attributes.push_val(fill_and_stroke); @@ -1046,23 +1026,7 @@ impl GraphicElementRendered for RasterDataTable { // Unlike path and g elements, the mask attribute of image element is broken and // behaves differently across different browsers. And so we use g to have it work correctly. if let Some(mask) = instance.mask { - render.parent_tag( - "g", - |attributes| { - let uuid = generate_uuid(); - let mask_type = if mask.can_reduce_to_clip_path() { MaskType::Clip } else { MaskType::Mask }; - let mut svg = SvgRender::new(); - mask.render_svg(&mut svg, &render_params.for_clipper()); - - write!(&mut attributes.0.svg_defs, r##"{}"##, svg.svg_defs).unwrap(); - mask_type.write_to_defs(&mut attributes.0.svg_defs, uuid, svg.svg.to_svg_string()); - let id = format!("mask-{}", uuid); - let selector = format!("url(#{id})"); - - attributes.push(mask_type.to_attribute(), selector); - }, - render_image, - ); + render.parent_tag("g", |attributes| attributes.push_mask(mask, render_params.for_clipper()), render_image); } else { render_image(render) } @@ -1383,4 +1347,17 @@ impl SvgRenderAttrs<'_> { pub fn push_val(&mut self, value: impl Into) { self.0.svg.push(value.into()); } + fn push_mask(&mut self, mask: &GraphicElement, render_params: RenderParams) { + let uuid = generate_uuid(); + let mut svg = SvgRender::new(); + mask.render_svg(&mut svg, &render_params); + + let id = format!("mask-{}", uuid); + write!(&mut self.0.svg_defs, r##"{}"##, svg.svg_defs).unwrap(); + write!(&mut self.0.svg_defs, r##"{}"##, svg.svg.to_svg_string()).unwrap(); + + let selector = format!("url(#{id})"); + + self.push("mask", selector); + } } From 9f3a19f648a81ec34b846e902e1ed40e16372f68 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Tue, 15 Jul 2025 14:11:06 +0530 Subject: [PATCH 09/11] add: vello luminance based clipping --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- node-graph/gsvg-renderer/src/renderer.rs | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5487e27d28..3949c769ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4364,7 +4364,7 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "peniko" version = "0.2.0" -source = "git+https://github.com/linebender/peniko.git?rev=d114c62#d114c6292dbcfb03e7360692198be423168a0edd" +source = "git+https://github.com/mTvare6/peniko.git?branch=luminance-clip#cd9aa45fe5a5c3070f18311cf33aad9cc83e5863" dependencies = [ "color 0.1.0", "kurbo", @@ -7273,7 +7273,7 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vello" version = "0.3.0" -source = "git+https://github.com/linebender/vello.git?rev=3275ec8#3275ec85d831180be81820de06cca29a97a757f5" +source = "git+https://github.com/mTvare6/vello.git?branch=luminance-clip#8af3207bd009da4e893b29f199985924e4a0b696" dependencies = [ "bytemuck", "futures-intrusive", @@ -7291,7 +7291,7 @@ dependencies = [ [[package]] name = "vello_encoding" version = "0.3.0" -source = "git+https://github.com/linebender/vello.git?rev=3275ec8#3275ec85d831180be81820de06cca29a97a757f5" +source = "git+https://github.com/mTvare6/vello.git?branch=luminance-clip#8af3207bd009da4e893b29f199985924e4a0b696" dependencies = [ "bytemuck", "guillotiere", @@ -7303,7 +7303,7 @@ dependencies = [ [[package]] name = "vello_shaders" version = "0.3.0" -source = "git+https://github.com/linebender/vello.git?rev=3275ec8#3275ec85d831180be81820de06cca29a97a757f5" +source = "git+https://github.com/mTvare6/vello.git?branch=luminance-clip#8af3207bd009da4e893b29f199985924e4a0b696" dependencies = [ "bytemuck", "naga", diff --git a/Cargo.toml b/Cargo.toml index 35c5e7040d..0adcac31ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -114,7 +114,7 @@ web-sys = { version = "=0.3.77", features = [ winit = "0.29" url = "2.5" tokio = { version = "1.29", features = ["fs", "macros", "io-std", "rt"] } -vello = { git = "https://github.com/linebender/vello.git", rev = "3275ec8" } # TODO switch back to stable when a release is made +vello = { git = "https://github.com/mTvare6/vello.git", branch = "luminance-clip" } # TODO switch back to stable when a release is made resvg = "0.44" usvg = "0.44" rand = { version = "0.9", default-features = false, features = ["std_rng"] } diff --git a/node-graph/gsvg-renderer/src/renderer.rs b/node-graph/gsvg-renderer/src/renderer.rs index 658813d487..ecb42905ae 100644 --- a/node-graph/gsvg-renderer/src/renderer.rs +++ b/node-graph/gsvg-renderer/src/renderer.rs @@ -329,7 +329,7 @@ impl GraphicElementRendered for GraphicGroupTable { scene.push_layer(peniko::Mix::Normal, 1., kurbo::Affine::IDENTITY, &rect); mask.render_to_vello(scene, transform, context, &render_params.for_clipper()); - scene.push_layer(peniko::BlendMode::new(peniko::Mix::Clip, peniko::Compose::SrcIn), 1., kurbo::Affine::IDENTITY, &rect); + scene.push_layer(peniko::BlendMode::new(peniko::Mix::LuminanceClip, peniko::Compose::SrcIn), 1., kurbo::Affine::IDENTITY, &rect); } } @@ -593,7 +593,7 @@ impl GraphicElementRendered for VectorDataTable { scene.push_layer(peniko::Mix::Normal, 1., kurbo::Affine::IDENTITY, &rect); mask.render_to_vello(scene, element_transform, _context, &render_params.for_clipper()); - scene.push_layer(peniko::BlendMode::new(peniko::Mix::Clip, peniko::Compose::SrcIn), 1., kurbo::Affine::IDENTITY, &rect); + scene.push_layer(peniko::BlendMode::new(peniko::Mix::LuminanceClip, peniko::Compose::SrcIn), 1., kurbo::Affine::IDENTITY, &rect); } } @@ -1055,7 +1055,7 @@ impl GraphicElementRendered for RasterDataTable { scene.push_layer(peniko::Mix::Normal, 1., kurbo::Affine::IDENTITY, &rect); mask.render_to_vello(scene, transform, _context, &render_params.for_clipper()); - scene.push_layer(peniko::BlendMode::new(peniko::Mix::Clip, peniko::Compose::SrcIn), 1., kurbo::Affine::IDENTITY, &rect); + scene.push_layer(peniko::BlendMode::new(peniko::Mix::LuminanceClip, peniko::Compose::SrcIn), 1., kurbo::Affine::IDENTITY, &rect); } } @@ -1354,7 +1354,7 @@ impl SvgRenderAttrs<'_> { let id = format!("mask-{}", uuid); write!(&mut self.0.svg_defs, r##"{}"##, svg.svg_defs).unwrap(); - write!(&mut self.0.svg_defs, r##"{}"##, svg.svg.to_svg_string()).unwrap(); + write!(&mut self.0.svg_defs, r##"{}"##, svg.svg.to_svg_string()).unwrap(); let selector = format!("url(#{id})"); From 33ba003ecdffa4ccf1b66d538d6c98fd896dca21 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 16 Jul 2025 06:44:55 +0530 Subject: [PATCH 10/11] fix: fix mode detection --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3949c769ff..efbf39ca37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7273,7 +7273,7 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vello" version = "0.3.0" -source = "git+https://github.com/mTvare6/vello.git?branch=luminance-clip#8af3207bd009da4e893b29f199985924e4a0b696" +source = "git+https://github.com/mTvare6/vello.git?branch=luminance-clip#0e60fee95c8a7c53cc49e4a8a79a9130496772b5" dependencies = [ "bytemuck", "futures-intrusive", @@ -7291,7 +7291,7 @@ dependencies = [ [[package]] name = "vello_encoding" version = "0.3.0" -source = "git+https://github.com/mTvare6/vello.git?branch=luminance-clip#8af3207bd009da4e893b29f199985924e4a0b696" +source = "git+https://github.com/mTvare6/vello.git?branch=luminance-clip#0e60fee95c8a7c53cc49e4a8a79a9130496772b5" dependencies = [ "bytemuck", "guillotiere", @@ -7303,7 +7303,7 @@ dependencies = [ [[package]] name = "vello_shaders" version = "0.3.0" -source = "git+https://github.com/mTvare6/vello.git?branch=luminance-clip#8af3207bd009da4e893b29f199985924e4a0b696" +source = "git+https://github.com/mTvare6/vello.git?branch=luminance-clip#0e60fee95c8a7c53cc49e4a8a79a9130496772b5" dependencies = [ "bytemuck", "naga", From d873399a584ee7072bdc4e6613e7f66ec82ecb69 Mon Sep 17 00:00:00 2001 From: mtvare6 Date: Wed, 16 Jul 2025 06:57:10 +0530 Subject: [PATCH 11/11] fix: previous fix --- Cargo.lock | 206 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 138 insertions(+), 68 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index efbf39ca37..71611c5faa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -290,9 +290,9 @@ dependencies = [ [[package]] name = "avif-serialize" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19135c0c7a60bfee564dbe44ab5ce0557c6bf3884e5291a50be76a15640c4fbd" +checksum = "2ea8ef51aced2b9191c08197f55450d830876d9933f8f48a429b354f1d496b42" dependencies = [ "arrayvec", ] @@ -666,7 +666,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02260d489095346e5cafd04dea8e8cb54d1d74fcd759022a9b72986ebe9a1257" dependencies = [ "serde", - "toml", + "toml 0.8.23", ] [[package]] @@ -677,9 +677,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.27" +version = "1.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" dependencies = [ "jobserver", "libc", @@ -775,9 +775,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.40" +version = "4.5.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" +checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9" dependencies = [ "clap_builder", "clap_derive", @@ -785,9 +785,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.40" +version = "4.5.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" +checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d" dependencies = [ "anstream", "anstyle", @@ -797,9 +797,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.40" +version = "4.5.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" +checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -1016,9 +1016,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -1401,14 +1401,14 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "embed-resource" -version = "3.0.4" +version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0963f530273dc3022ab2bdc3fcd6d488e850256f2284a82b7413cb9481ee85dd" +checksum = "4c6d81016d6c977deefb2ef8d8290da019e27cc26167e102185da528e6c0ab38" dependencies = [ "cc", "memchr", "rustc_version", - "toml", + "toml 0.9.2", "vswhom", "winreg", ] @@ -2751,9 +2751,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" +checksum = "7f66d5bd4c6f02bf0542fad85d626775bab9258cf795a4256dcaf3161114d1df" dependencies = [ "base64 0.22.1", "bytes", @@ -3100,6 +3100,17 @@ dependencies = [ "wgpu-executor", ] +[[package]] +name = "io-uring" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" +dependencies = [ + "bitflags 2.9.1", + "cfg-if", + "libc", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -3388,9 +3399,9 @@ checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "libfuzzer-sys" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf78f52d400cf2d84a3a973a78a592b4adc535739e0a5597a0da6f0c357adc75" +checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404" dependencies = [ "arbitrary", "cc", @@ -3586,9 +3597,9 @@ checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "memmap2" -version = "0.9.5" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +checksum = "483758ad303d734cec05e5c12b41d7e93e6a6390c5e9dae6bdeb7c1259012d28" dependencies = [ "libc", ] @@ -4612,13 +4623,13 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "plist" -version = "1.7.2" +version = "1.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d77244ce2d584cd84f6a15f86195b8c9b2a0dfbfd817c09e0464244091a58ed" +checksum = "3af6b589e163c5a788fab00ce0c0366f6efbb9959c2f9874b224936af7fce7e1" dependencies = [ "base64 0.22.1", "indexmap 2.10.0", - "quick-xml", + "quick-xml 0.38.0", "serde", "time", ] @@ -4674,7 +4685,7 @@ dependencies = [ "concurrent-queue", "hermit-abi", "pin-project-lite", - "rustix 1.0.7", + "rustix 1.0.8", "tracing", "windows-sys 0.59.0", ] @@ -4897,6 +4908,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "quick-xml" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8927b0664f5c5a98265138b7e3f90aa19a6b21353182469ace36d4ac527b7b1b" +dependencies = [ + "memchr", +] + [[package]] name = "quinn" version = "0.11.8" @@ -5348,9 +5368,9 @@ dependencies = [ [[package]] name = "rgb" -version = "0.8.50" +version = "0.8.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce" dependencies = [ "bytemuck", ] @@ -5429,22 +5449,22 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ "bitflags 2.9.1", "errno", "libc", "linux-raw-sys 0.9.4", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "rustls" -version = "0.23.28" +version = "0.23.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643" +checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1" dependencies = [ "once_cell", "ring", @@ -5466,9 +5486,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.3" +version = "0.103.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" +checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" dependencies = [ "ring", "rustls-pki-types", @@ -5552,9 +5572,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1375ba8ef45a6f15d83fa8748f1079428295d403d6ea991d09ab100155fbc06d" +checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" dependencies = [ "dyn-clone", "ref-cast", @@ -5744,6 +5764,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -5768,7 +5797,7 @@ dependencies = [ "indexmap 1.9.3", "indexmap 2.10.0", "schemars 0.9.0", - "schemars 1.0.3", + "schemars 1.0.4", "serde", "serde_derive", "serde_json", @@ -5833,9 +5862,9 @@ dependencies = [ [[package]] name = "shared_child" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2778001df1384cf20b6dc5a5a90f48da35539885edaaefd887f8d744e939c0b" +checksum = "1e362d9935bc50f019969e2f9ecd66786612daae13e8f277be7bfb66e8bed3f7" dependencies = [ "libc", "sigchld", @@ -5850,9 +5879,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "sigchld" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1219ef50fc0fdb04fcc243e6aa27f855553434ffafe4fa26554efb78b5b4bf89" +checksum = "47106eded3c154e70176fc83df9737335c94ce22f821c32d17ed1db1f83badb1" dependencies = [ "libc", "os_pipe", @@ -6275,7 +6304,7 @@ dependencies = [ "cfg-expr", "heck 0.5.0", "pkg-config", - "toml", + "toml 0.8.23", "version-compare", ] @@ -6403,7 +6432,7 @@ dependencies = [ "serde_json", "tauri-utils", "tauri-winres", - "toml", + "toml 0.8.23", "walkdir", ] @@ -6461,7 +6490,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "toml", + "toml 0.8.23", "walkdir", ] @@ -6483,7 +6512,7 @@ dependencies = [ "tauri-plugin", "tauri-utils", "thiserror 2.0.12", - "toml", + "toml 0.8.23", "url", ] @@ -6612,7 +6641,7 @@ dependencies = [ "serde_with", "swift-rs", "thiserror 2.0.12", - "toml", + "toml 0.8.23", "url", "urlpattern", "uuid", @@ -6627,7 +6656,7 @@ checksum = "e8d321dbc6f998d825ab3f0d62673e810c861aac2d0de2cc2c395328f1d113b4" dependencies = [ "embed-resource", "indexmap 2.10.0", - "toml", + "toml 0.8.23", ] [[package]] @@ -6639,7 +6668,7 @@ dependencies = [ "fastrand", "getrandom 0.3.3", "once_cell", - "rustix 1.0.7", + "rustix 1.0.8", "windows-sys 0.59.0", ] @@ -6817,15 +6846,17 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.45.1" +version = "1.46.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" dependencies = [ "backtrace", "bytes", + "io-uring", "libc", "mio", "pin-project-lite", + "slab", "socket2", "tokio-macros", "windows-sys 0.52.0", @@ -6882,11 +6913,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", "toml_edit 0.22.27", ] +[[package]] +name = "toml" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed0aee96c12fa71097902e0bb061a5e1ebd766a6636bb605ba401c45c1650eac" +dependencies = [ + "indexmap 2.10.0", + "serde", + "serde_spanned 1.0.0", + "toml_datetime 0.7.0", + "toml_parser", + "toml_writer", + "winnow 0.7.12", +] + [[package]] name = "toml_datetime" version = "0.6.11" @@ -6896,6 +6942,15 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" +dependencies = [ + "serde", +] + [[package]] name = "toml_edit" version = "0.19.15" @@ -6903,7 +6958,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.10.0", - "toml_datetime", + "toml_datetime 0.6.11", "winnow 0.5.40", ] @@ -6914,7 +6969,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ "indexmap 2.10.0", - "toml_datetime", + "toml_datetime 0.6.11", "winnow 0.5.40", ] @@ -6926,10 +6981,19 @@ checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap 2.10.0", "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", "toml_write", - "winnow 0.7.11", + "winnow 0.7.12", +] + +[[package]] +name = "toml_parser" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30" +dependencies = [ + "winnow 0.7.12", ] [[package]] @@ -6938,6 +7002,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +[[package]] +name = "toml_writer" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" + [[package]] name = "tower" version = "0.5.2" @@ -7273,7 +7343,7 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vello" version = "0.3.0" -source = "git+https://github.com/mTvare6/vello.git?branch=luminance-clip#0e60fee95c8a7c53cc49e4a8a79a9130496772b5" +source = "git+https://github.com/mTvare6/vello.git?branch=luminance-clip#cbe3d204cdbe3dd45716ffac6109da1390ec9536" dependencies = [ "bytemuck", "futures-intrusive", @@ -7291,7 +7361,7 @@ dependencies = [ [[package]] name = "vello_encoding" version = "0.3.0" -source = "git+https://github.com/mTvare6/vello.git?branch=luminance-clip#0e60fee95c8a7c53cc49e4a8a79a9130496772b5" +source = "git+https://github.com/mTvare6/vello.git?branch=luminance-clip#cbe3d204cdbe3dd45716ffac6109da1390ec9536" dependencies = [ "bytemuck", "guillotiere", @@ -7303,7 +7373,7 @@ dependencies = [ [[package]] name = "vello_shaders" version = "0.3.0" -source = "git+https://github.com/mTvare6/vello.git?branch=luminance-clip#0e60fee95c8a7c53cc49e4a8a79a9130496772b5" +source = "git+https://github.com/mTvare6/vello.git?branch=luminance-clip#cbe3d204cdbe3dd45716ffac6109da1390ec9536" dependencies = [ "bytemuck", "naga", @@ -7560,7 +7630,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" dependencies = [ "proc-macro2", - "quick-xml", + "quick-xml 0.37.5", "quote", ] @@ -8413,9 +8483,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" dependencies = [ "memchr", ] @@ -8564,9 +8634,9 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] name = "xml-rs" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda" +checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7" [[package]] name = "xmlwriter" @@ -8713,9 +8783,9 @@ dependencies = [ [[package]] name = "zune-jpeg" -version = "0.4.18" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7384255a918371b5af158218d131530f694de9ad3815ebdd0453a940485cb0fa" +checksum = "2c9e525af0a6a658e031e95f14b7f889976b74a11ba0eca5a5fc9ac8a1c43a6a" dependencies = [ "zune-core", ]