Move the downstream-typed attribute markers to their value types' crates

This commit is contained in:
Dennis Kobert
2026-08-22 09:34:17 +00:00
parent 49c592013c
commit a8d257e7d6
17 changed files with 132 additions and 39 deletions

View File

@@ -31,9 +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_CLICK_TARGET, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_EDITOR_TEXT_FRAME, ATTR_END,
ATTR_FONT, ATTR_FONT_SIZE, ATTR_GRADIENT_TYPE, 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_SPREAD_METHOD, ATTR_START, ATTR_TEXT_ALIGN, ATTR_TRANSFORM, ATTR_TYPE,
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,
};
pub use memo::MemoHash;
pub use no_std_types::AsU32;

View File

@@ -36,29 +36,17 @@ 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 below core-types. Their markers and
// constants move to the crates that own those types with the marker wave.
// 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";
/// 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.
pub const ATTR_EDITOR_CLICK_TARGET: &str = "editor:click_target";
/// Gradient's `GradientSpreadMethod` (`Pad`, `Reflect`, or `Repeat`).
pub const ATTR_SPREAD_METHOD: &str = "spread_method";
/// Gradient's `GradientType` (`Linear` or `Radial`).
pub const ATTR_GRADIENT_TYPE: &str = "gradient_type";
/// 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";
/// Text item's font, as a `Resource` of the loaded font file.
pub const ATTR_FONT: &str = "font";
/// Text item's `TextAlign` horizontal alignment of lines within the block.
pub const ATTR_TEXT_ALIGN: &str = "text_align";
// ===========================
// Implicit attribute defaults

View File

@@ -933,8 +933,7 @@ mod tests {
#[cfg(test)]
mod graphic_is_opaque_tests {
use core_types::ATTR_SPREAD_METHOD;
use vector_types::{GradientSpreadMethod, GradientStop};
use vector_types::{ATTR_SPREAD_METHOD, GradientSpreadMethod, GradientStop};
use super::*;

View File

@@ -3,14 +3,14 @@ use crate::{Render, RenderSvgSegmentList, SvgRender};
use core_types::color::SRGBA8;
use core_types::list::List;
use core_types::uuid::generate_uuid;
use core_types::{ATTR_GRADIENT_TYPE, ATTR_SPREAD_METHOD, ATTR_TRANSFORM, Color};
use core_types::{ATTR_TRANSFORM, Color};
use glam::{DAffine2, DVec2};
use graphic_types::Graphic;
use graphic_types::vector_types::gradient::GradientType;
use graphic_types::vector_types::vector::style::{PaintOrder, Stroke, StrokeAlign, StrokeCap, StrokeJoin};
use std::fmt::Write;
use vector_types::GradientStops;
use vector_types::gradient::GradientSpreadMethod;
use vector_types::{ATTR_GRADIENT_TYPE, ATTR_SPREAD_METHOD, GradientStops};
#[derive(Copy, Clone, PartialEq)]
pub enum PaintTarget {

View File

@@ -13,9 +13,8 @@ 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_CLICK_TARGET, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_EDITOR_TEXT_FRAME, ATTR_FONT,
ATTR_FONT_SIZE, ATTR_GRADIENT_TYPE, ATTR_LETTER_SPACING, ATTR_LETTER_TILT, ATTR_LINE_HEIGHT, ATTR_LOCATION, ATTR_MAX_HEIGHT, ATTR_MAX_WIDTH, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_SPREAD_METHOD,
ATTR_TEXT_ALIGN, ATTR_TRANSFORM,
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,
};
use dyn_any::DynAny;
use glam::{DAffine2, DMat2, DVec2};
@@ -39,7 +38,9 @@ use std::fmt::Write;
use std::hash::Hash;
use std::ops::Deref;
use std::sync::{Arc, LazyLock};
use text_nodes::{ATTR_FONT, ATTR_TEXT_ALIGN};
use vector_types::gradient::GradientSpreadMethod;
use vector_types::{ATTR_EDITOR_CLICK_TARGET, ATTR_GRADIENT_TYPE, ATTR_SPREAD_METHOD};
use vello::*;
#[derive(Clone, Copy, Debug, PartialEq)]

View File

@@ -38,6 +38,13 @@ impl Default for Resource {
}
}
impl Default for &Resource {
fn default() -> Self {
static EMPTY: std::sync::LazyLock<Resource> = std::sync::LazyLock::new(Resource::empty);
std::sync::LazyLock::force(&EMPTY)
}
}
impl From<&Resource> for Arc<dyn AsRef<[u8]> + Send + Sync> {
fn from(val: &Resource) -> Self {
val.inner.clone()

View File

@@ -2,6 +2,7 @@
extern crate log;
pub mod gradient;
pub mod markers;
pub mod math;
pub mod subpath;
pub mod vector;
@@ -9,6 +10,7 @@ pub mod vector;
// Re-export commonly used types at the crate root
pub use core_types as gcore;
pub use gradient::{GradientSpreadMethod, GradientStop, GradientStops, GradientType};
pub use markers::{ATTR_EDITOR_CLICK_TARGET, ATTR_GRADIENT_TYPE, ATTR_SPREAD_METHOD};
pub use math::{QuadExt, RectExt};
pub use subpath::Subpath;
pub use vector::Vector;

View File

@@ -0,0 +1,65 @@
//! Attribute markers whose value types live in this crate, with their name
//! 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 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;
#[cfg(test)]
mod tests {
use super::*;
use core_types::attribute::info;
use std::any::TypeId;
#[test]
fn the_census_carries_this_crates_names() {
assert_eq!(info("gradient_type").unwrap().value_type, TypeId::of::<crate::gradient::GradientType>());
assert_eq!(info("spread_method").unwrap().value_type, TypeId::of::<crate::gradient::GradientSpreadMethod>());
assert_eq!(info("editor:click_target").unwrap().value_type, TypeId::of::<Option<&'static crate::Vector>>());
}
#[test]
fn an_absent_click_target_defaults_to_none() {
assert_eq!(<EditorClickTarget as Attribute>::default(), None);
}
}