mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Move the paint and merged-layer markers to graphic-types as optional references
This commit is contained in:
@@ -164,10 +164,45 @@ pub fn default_value(name: &str) -> Option<Box<dyn AnyAttributeValue>> {
|
||||
///
|
||||
/// The trailing `= expr` is the name-specific default; without it the value
|
||||
/// type's `Default` applies. A `&T` value carries the eval lifetime, so its
|
||||
/// default must be `'static` data.
|
||||
/// default must be `'static` data. An `Option<&T>` value is an optional
|
||||
/// parked reference whose default is `None`, for attributes whose absence
|
||||
/// means something a present value cannot.
|
||||
#[macro_export]
|
||||
macro_rules! attribute {
|
||||
() => {};
|
||||
($(#[$meta:meta])* $vis:vis $marker:ident($name:literal): Option<&$value:ty>; $($rest:tt)*) => {
|
||||
$(#[$meta])*
|
||||
$vis struct $marker;
|
||||
|
||||
impl $crate::attribute::Attribute for $marker {
|
||||
const NAME: &'static str = $name;
|
||||
type Value<'e> = ::core::option::Option<&'e $value>;
|
||||
|
||||
unsafe fn read_erased(ptr: *const u8) -> ::std::boxed::Box<dyn $crate::list::AnyAttributeValue> {
|
||||
::std::boxed::Box::new(unsafe { ptr.cast::<::core::option::Option<&$value>>().read() }.map(|value| <$value as ::std::borrow::ToOwned>::to_owned(value)))
|
||||
}
|
||||
|
||||
const REPARK: ::core::option::Option<unsafe fn(&dyn $crate::list::AnyAttributeValue, *mut u8, &$crate::arena::Arena) -> ::core::option::Option<()>> = {
|
||||
unsafe fn repark(value: &dyn $crate::list::AnyAttributeValue, dst: *mut u8, arena: &$crate::arena::Arena) -> ::core::option::Option<()> {
|
||||
let owned: &::core::option::Option<<$value as ::std::borrow::ToOwned>::Owned> =
|
||||
value.as_any().downcast_ref().expect("an optional reference attribute replays its owned clone");
|
||||
let parked = match owned {
|
||||
::core::option::Option::Some(owned) => {
|
||||
let (parked, _) = arena.alloc(<$value as ::std::borrow::ToOwned>::to_owned(::std::borrow::Borrow::borrow(owned)))?;
|
||||
::core::option::Option::Some(::std::borrow::Borrow::borrow(parked))
|
||||
}
|
||||
::core::option::Option::None => ::core::option::Option::None,
|
||||
};
|
||||
unsafe { dst.cast::<::core::option::Option<&$value>>().write(parked) };
|
||||
::core::option::Option::Some(())
|
||||
}
|
||||
::core::option::Option::Some(repark)
|
||||
};
|
||||
}
|
||||
|
||||
$crate::attribute!(@register $marker);
|
||||
$crate::attribute!($($rest)*);
|
||||
};
|
||||
($(#[$meta:meta])* $vis:vis $marker:ident($name:literal): &$value:ty $(= $default:expr)?; $($rest:tt)*) => {
|
||||
$(#[$meta])*
|
||||
$vis struct $marker;
|
||||
|
||||
@@ -31,8 +31,8 @@ pub use dyn_any::{StaticTypeSized, WasmNotSend, WasmNotSync};
|
||||
pub use graphene_hash;
|
||||
pub use graphene_hash::CacheHash;
|
||||
pub use list::{
|
||||
ATTR_BACKGROUND, ATTR_BLEND_MODE, ATTR_CLIP, ATTR_CLIPPING_MASK, ATTR_DIMENSIONS, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_EDITOR_TEXT_FRAME, ATTR_END, ATTR_FONT_SIZE,
|
||||
ATTR_LETTER_SPACING, ATTR_LETTER_TILT, ATTR_LINE_HEIGHT, ATTR_LOCATION, ATTR_MAX_HEIGHT, ATTR_MAX_WIDTH, ATTR_NAME, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_START, ATTR_TRANSFORM, ATTR_TYPE,
|
||||
ATTR_BACKGROUND, ATTR_BLEND_MODE, ATTR_CLIP, ATTR_CLIPPING_MASK, ATTR_DIMENSIONS, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_TEXT_FRAME, ATTR_END, ATTR_FONT_SIZE, ATTR_LETTER_SPACING, ATTR_LETTER_TILT,
|
||||
ATTR_LINE_HEIGHT, ATTR_LOCATION, ATTR_MAX_HEIGHT, ATTR_MAX_WIDTH, ATTR_NAME, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_START, ATTR_TRANSFORM, ATTR_TYPE,
|
||||
};
|
||||
pub use memo::MemoHash;
|
||||
pub use no_std_types::AsU32;
|
||||
|
||||
@@ -10,9 +10,11 @@ use std::fmt::Debug;
|
||||
// =================================================
|
||||
// Standard attribute keys used across the data flow
|
||||
// =================================================
|
||||
// Each name is declared once by its marker in [`crate::attribute`], which
|
||||
// documents the attribute and fixes its value type. The constants re-export
|
||||
// the markers' names for the string-keyed legacy readers and writers.
|
||||
// Each name is declared once by its marker, which documents the attribute and
|
||||
// fixes its value type. The constants re-export the markers' names for the
|
||||
// string-keyed legacy readers and writers. Markers whose value types live
|
||||
// below core-types are declared in their types' crates (vector-types, the
|
||||
// text nodes, graphic-types), each with its own name constants.
|
||||
|
||||
pub const ATTR_TRANSFORM: &str = crate::attribute::Transform::NAME;
|
||||
pub const ATTR_BLEND_MODE: &str = crate::attribute::BlendMode::NAME;
|
||||
@@ -36,18 +38,6 @@ pub const ATTR_MAX_WIDTH: &str = crate::attribute::MaxWidth::NAME;
|
||||
pub const ATTR_MAX_HEIGHT: &str = crate::attribute::MaxHeight::NAME;
|
||||
pub const ATTR_LETTER_TILT: &str = crate::attribute::LetterTilt::NAME;
|
||||
|
||||
// The remaining names' value types live in graphic-types. Their markers and
|
||||
// constants move there with the marker wave.
|
||||
|
||||
/// `List<Graphic>` snapshot of the upstream content that fed into a destructive merge
|
||||
/// (Boolean Operation, Rasterize, etc.), so the editor can still surface click targets for
|
||||
/// the original child layers after their content has been collapsed.
|
||||
pub const ATTR_EDITOR_MERGED_LAYERS: &str = "editor:merged_layers";
|
||||
/// Vector graphics object's filled area paint, of type List<T> where T is any graphic type.
|
||||
pub const ATTR_FILL: &str = "fill";
|
||||
/// Vector graphics object's stroke paint, of type List<T> where T is any graphic type.
|
||||
pub const ATTR_STROKE: &str = "stroke";
|
||||
|
||||
// ===========================
|
||||
// Implicit attribute defaults
|
||||
// ===========================
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use core_types::bounds::{BoundingBox, RenderBoundingBox};
|
||||
use core_types::graphene_hash::CacheHash;
|
||||
use core_types::list::{ATTR_FILL, ATTR_STROKE, AttributeValueDyn, Item, ItemAttributeValues, List};
|
||||
use crate::markers::{ATTR_FILL, ATTR_STROKE};
|
||||
use core_types::list::{AttributeValueDyn, Item, ItemAttributeValues, List};
|
||||
use core_types::ops::{FromAnchorPosition, ListConvert};
|
||||
use core_types::render_complexity::RenderComplexity;
|
||||
use core_types::uuid::NodeId;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
pub mod artboard;
|
||||
pub mod graphic;
|
||||
pub mod markers;
|
||||
|
||||
// Re-export all transitive dependencies so downstream crates only need to depend on graphic-types
|
||||
pub use core_types;
|
||||
@@ -9,6 +10,7 @@ pub use vector_types;
|
||||
// Re-export commonly used types at the crate root
|
||||
pub use artboard::Artboard;
|
||||
pub use graphic::{Graphic, IntoGraphicList, TryFromGraphic, Vector};
|
||||
pub use markers::{ATTR_EDITOR_MERGED_LAYERS, ATTR_FILL, ATTR_STROKE};
|
||||
|
||||
pub mod migrations {
|
||||
use crate::Vector;
|
||||
|
||||
45
node-graph/libraries/graphic-types/src/markers.rs
Normal file
45
node-graph/libraries/graphic-types/src/markers.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
//! Attribute markers whose value types live in this crate, with their name
|
||||
//! constants for the string-keyed legacy readers and writers.
|
||||
//!
|
||||
//! The list-valued markers deep-copy by cloning the list, so their values must
|
||||
//! stay free of arena-borrowing content such as [`Graphic::Group`].
|
||||
|
||||
use crate::Graphic;
|
||||
use core_types::attribute::Attribute;
|
||||
use core_types::list::List;
|
||||
|
||||
core_types::attribute! {
|
||||
/// Vector graphics object's filled area paint, a graphic list in the canonical paint form.
|
||||
/// An absent value means no fill.
|
||||
pub Fill("fill"): Option<&List<Graphic>>;
|
||||
/// Vector graphics object's stroke paint, a graphic list in the canonical paint form.
|
||||
/// An absent value means no stroke paint.
|
||||
pub Stroke("stroke"): Option<&List<Graphic>>;
|
||||
/// Snapshot of the upstream content that fed into a destructive merge (Boolean Operation,
|
||||
/// Rasterize, etc.), so the editor can still surface click targets for the original child
|
||||
/// layers after their content has been collapsed.
|
||||
pub EditorMergedLayers("editor:merged_layers"): Option<&List<Graphic>>;
|
||||
}
|
||||
|
||||
pub const ATTR_FILL: &str = Fill::NAME;
|
||||
pub const ATTR_STROKE: &str = Stroke::NAME;
|
||||
pub const ATTR_EDITOR_MERGED_LAYERS: &str = EditorMergedLayers::NAME;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use core_types::attribute::info;
|
||||
use std::any::TypeId;
|
||||
|
||||
#[test]
|
||||
fn the_census_carries_this_crates_names() {
|
||||
for name in ["fill", "stroke", "editor:merged_layers"] {
|
||||
assert_eq!(info(name).unwrap().value_type, TypeId::of::<Option<&'static List<Graphic>>>());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_absent_paint_defaults_to_none() {
|
||||
assert_eq!(<Fill as Attribute>::default(), None);
|
||||
}
|
||||
}
|
||||
@@ -7,14 +7,14 @@ use core_types::bounds::RenderBoundingBox;
|
||||
use core_types::color::Color;
|
||||
use core_types::color::SRGBA8;
|
||||
use core_types::consts::DEFAULT_FONT_SIZE;
|
||||
use core_types::list::{ATTR_FILL, ATTR_STROKE, Item, List};
|
||||
use core_types::list::{Item, List};
|
||||
use core_types::math::quad::Quad;
|
||||
use core_types::render_complexity::RenderComplexity;
|
||||
use core_types::transform::Footprint;
|
||||
use core_types::uuid::{NodeId, generate_uuid};
|
||||
use core_types::{
|
||||
ATTR_BACKGROUND, ATTR_BLEND_MODE, ATTR_CLIP, ATTR_CLIPPING_MASK, ATTR_DIMENSIONS, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_EDITOR_TEXT_FRAME, ATTR_FONT_SIZE, ATTR_LETTER_SPACING,
|
||||
ATTR_LETTER_TILT, ATTR_LINE_HEIGHT, ATTR_LOCATION, ATTR_MAX_HEIGHT, ATTR_MAX_WIDTH, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_TRANSFORM,
|
||||
ATTR_BACKGROUND, ATTR_BLEND_MODE, ATTR_CLIP, ATTR_CLIPPING_MASK, ATTR_DIMENSIONS, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_TEXT_FRAME, ATTR_FONT_SIZE, ATTR_LETTER_SPACING, ATTR_LETTER_TILT,
|
||||
ATTR_LINE_HEIGHT, ATTR_LOCATION, ATTR_MAX_HEIGHT, ATTR_MAX_WIDTH, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_TRANSFORM,
|
||||
};
|
||||
use dyn_any::DynAny;
|
||||
use glam::{DAffine2, DMat2, DVec2};
|
||||
@@ -26,7 +26,7 @@ use graphic_types::vector_types::gradient::{GradientStops, GradientType};
|
||||
use graphic_types::vector_types::subpath::Subpath;
|
||||
use graphic_types::vector_types::vector::click_target::{ClickTarget, FreePoint};
|
||||
use graphic_types::vector_types::vector::style::{PaintOrder, RenderMode, StrokeAlign, StrokeCap, StrokeJoin};
|
||||
use graphic_types::{Artboard, Graphic, Vector};
|
||||
use graphic_types::{ATTR_EDITOR_MERGED_LAYERS, ATTR_FILL, ATTR_STROKE, Artboard, Graphic, Vector};
|
||||
use kurbo::{Affine, BezPath, Cap, Join, Shape, StrokeOpts};
|
||||
use num_traits::Zero;
|
||||
use skrifa::instance::{LocationRef, NormalizedCoord, Size};
|
||||
|
||||
@@ -2,45 +2,19 @@
|
||||
//! constants for the string-keyed legacy readers and writers.
|
||||
|
||||
use core_types::attribute::Attribute;
|
||||
use core_types::list::AnyAttributeValue;
|
||||
|
||||
core_types::attribute! {
|
||||
/// Gradient's spread behavior past its endpoints (`Pad`, `Reflect`, or `Repeat`).
|
||||
pub SpreadMethod("spread_method"): crate::gradient::GradientSpreadMethod;
|
||||
/// Gradient's shape (`Linear` or `Radial`).
|
||||
pub GradientType("gradient_type"): crate::gradient::GradientType;
|
||||
/// Optional `Vector` that overrides the item's own geometry for click-target generation.
|
||||
/// Used by the 'Text' node for per-glyph bounding-box rectangles so glyphs are selectable
|
||||
/// by clicking anywhere within their bounds, not just the filled letterform. An absent
|
||||
/// value means the item's own geometry is the click target.
|
||||
pub EditorClickTarget("editor:click_target"): Option<&crate::Vector>;
|
||||
}
|
||||
|
||||
/// Optional `Vector` that overrides the item's own geometry for click-target generation.
|
||||
/// Used by the 'Text' node for per-glyph bounding-box rectangles so glyphs are selectable
|
||||
/// by clicking anywhere within their bounds, not just the filled letterform. An absent
|
||||
/// value means the item's own geometry is the click target.
|
||||
pub struct EditorClickTarget;
|
||||
|
||||
impl Attribute for EditorClickTarget {
|
||||
const NAME: &'static str = "editor:click_target";
|
||||
type Value<'e> = Option<&'e crate::Vector>;
|
||||
|
||||
unsafe fn read_erased(ptr: *const u8) -> Box<dyn AnyAttributeValue> {
|
||||
Box::new(unsafe { ptr.cast::<Option<&crate::Vector>>().read() }.cloned())
|
||||
}
|
||||
|
||||
const REPARK: Option<unsafe fn(&dyn AnyAttributeValue, *mut u8, &core_types::arena::Arena) -> Option<()>> = {
|
||||
unsafe fn repark(value: &dyn AnyAttributeValue, dst: *mut u8, arena: &core_types::arena::Arena) -> Option<()> {
|
||||
let owned: &Option<crate::Vector> = value.as_any().downcast_ref().expect("an optional vector attribute replays its owned clone");
|
||||
let parked = match owned {
|
||||
Some(vector) => Some(arena.alloc(vector.clone())?.0),
|
||||
None => None,
|
||||
};
|
||||
unsafe { dst.cast::<Option<&crate::Vector>>().write(parked) };
|
||||
Some(())
|
||||
}
|
||||
Some(repark)
|
||||
};
|
||||
}
|
||||
|
||||
core_types::attribute!(@register EditorClickTarget);
|
||||
|
||||
pub const ATTR_SPREAD_METHOD: &str = SpreadMethod::NAME;
|
||||
pub const ATTR_GRADIENT_TYPE: &str = GradientType::NAME;
|
||||
pub const ATTR_EDITOR_CLICK_TARGET: &str = EditorClickTarget::NAME;
|
||||
|
||||
@@ -3,10 +3,10 @@ use core_types::gpoll::Interrupt;
|
||||
use core_types::list::{AttributeDyn, AttributeValueDyn, Item, List, ListDyn};
|
||||
use core_types::registry::types::{Angle, SignedInteger};
|
||||
use core_types::uuid::NodeId;
|
||||
use core_types::{ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_TRANSFORM, AnyHash, BlendMode, CacheHash, Color, Context, Ctx, DeriveCtx};
|
||||
use core_types::{ATTR_EDITOR_LAYER_PATH, ATTR_TRANSFORM, AnyHash, BlendMode, CacheHash, Color, Context, Ctx, DeriveCtx};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphic_types::graphic::{Graphic, IntoGraphicList};
|
||||
use graphic_types::{Artboard, Vector};
|
||||
use graphic_types::{ATTR_EDITOR_MERGED_LAYERS, Artboard, Vector};
|
||||
use raster_types::{CPU, GPU, Raster};
|
||||
use vector_types::gradient::{GradientSpreadMethod, GradientType};
|
||||
use vector_types::{GradientStop, GradientStops, ReferencePoint};
|
||||
|
||||
@@ -11,8 +11,10 @@ use core_types::runtime::SourceFuture;
|
||||
#[cfg(target_family = "wasm")]
|
||||
use core_types::transform::Footprint;
|
||||
#[cfg(target_family = "wasm")]
|
||||
use core_types::{ATTR_EDITOR_MERGED_LAYERS, ATTR_TRANSFORM, WasmNotSend};
|
||||
use core_types::{ATTR_TRANSFORM, WasmNotSend};
|
||||
use core_types::{Color, Ctx};
|
||||
#[cfg(target_family = "wasm")]
|
||||
use graphic_types::ATTR_EDITOR_MERGED_LAYERS;
|
||||
pub use graph_craft::application_io::resource::{Resource, ResourceHash};
|
||||
pub use graph_craft::application_io::*;
|
||||
pub use graph_craft::document::value::RenderOutputType;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use core_types::list::{ATTR_FILL, Item, List};
|
||||
use core_types::list::{Item, List};
|
||||
use core_types::uuid::NodeId;
|
||||
use core_types::{ATTR_BLEND_MODE, ATTR_CLIPPING_MASK, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_TRANSFORM, BlendMode, Color, Ctx};
|
||||
use core_types::{ATTR_BLEND_MODE, ATTR_CLIPPING_MASK, ATTR_EDITOR_LAYER_PATH, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_TRANSFORM, BlendMode, Color, Ctx};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphic_types::graphic::{bake_paint_transforms, set_paint_attribute};
|
||||
use graphic_types::vector_types::gradient::{GradientSpreadMethod, GradientType};
|
||||
@@ -8,7 +8,7 @@ use graphic_types::vector_types::{ATTR_GRADIENT_TYPE, ATTR_SPREAD_METHOD};
|
||||
use graphic_types::vector_types::subpath::{ManipulatorGroup, Subpath};
|
||||
use graphic_types::vector_types::vector::PointId;
|
||||
use graphic_types::vector_types::vector::algorithms::merge_by_distance::MergeByDistanceExt;
|
||||
use graphic_types::{Graphic, Vector};
|
||||
use graphic_types::{ATTR_EDITOR_MERGED_LAYERS, ATTR_FILL, Graphic, Vector};
|
||||
use linesweeper::topology::Topology;
|
||||
use linesweeper::{BinaryOp, FillRule, binary_op};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
@@ -4,16 +4,16 @@ use core::hash::{Hash, Hasher};
|
||||
use core_types::blending::BlendMode;
|
||||
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::{Item, ItemAttributeValues, List, ListDyn};
|
||||
use core_types::registry::types::{Angle, Length, Multiplier, Percentage, PixelLength, Progression, SeedValue};
|
||||
use core_types::transform::{Footprint, Transform};
|
||||
use core_types::uuid::NodeId;
|
||||
use core_types::{ATTR_BLEND_MODE, ATTR_CLIPPING_MASK, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_TRANSFORM, Color, Ctx, DeriveCtx};
|
||||
use core_types::{ATTR_BLEND_MODE, ATTR_CLIPPING_MASK, ATTR_EDITOR_LAYER_PATH, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_TRANSFORM, Color, Ctx, DeriveCtx};
|
||||
use glam::{DAffine2, DMat2, DVec2};
|
||||
use graphic_types::Vector;
|
||||
use graphic_types::graphic::{bake_paint_transforms, graphic_list_at, has_paint_at, is_paint_present, set_paint_attribute_at};
|
||||
use graphic_types::raster_types::{CPU, GPU, Raster};
|
||||
use graphic_types::{Graphic, IntoGraphicList};
|
||||
use graphic_types::{ATTR_EDITOR_MERGED_LAYERS, ATTR_FILL, ATTR_STROKE, Graphic, IntoGraphicList};
|
||||
use kurbo::simplify::{SimplifyOptions, simplify_bezpath};
|
||||
use kurbo::{Affine, BezPath, DEFAULT_ACCURACY, Line, ParamCurve, ParamCurveArclen, PathEl, PathSeg, Shape};
|
||||
use rand::{Rng, SeedableRng};
|
||||
|
||||
Reference in New Issue
Block a user