mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Adopt serving lifetimes and the safe record surfaces in the node crates
This commit is contained in:
@@ -8,7 +8,7 @@ use graphic_types::{Graphic, Vector};
|
||||
use raster_types::{CPU, Raster};
|
||||
|
||||
#[node_macro::node(category("Context"), path(graphene_core::vector))]
|
||||
fn read_graphic(ctx: impl Ctx + ExtractVarArgs) -> List<Graphic> {
|
||||
fn read_graphic(ctx: impl Ctx + ExtractVarArgs) -> List<Graphic<'static>> {
|
||||
let Ok(var_arg) = ctx.vararg(0) else { return Default::default() };
|
||||
let var_arg = var_arg as &dyn std::any::Any;
|
||||
|
||||
@@ -71,7 +71,7 @@ fn vararg_element<T: Clone + 'static>(ctx: &(impl ExtractVarArgs + ExtractIndex)
|
||||
|
||||
/// Rank-model vararg source: the mapped row's items as lanes, elements only.
|
||||
#[node_macro::node(category("Test"), extent_raw(read_graphic_row_extent))]
|
||||
pub fn read_graphic_row(ctx: impl Ctx + ExtractVarArgs + ExtractIndex) -> Result<IList<Graphic>, Interrupt> {
|
||||
pub fn read_graphic_row(ctx: impl Ctx + ExtractVarArgs + ExtractIndex) -> Result<IList<Graphic<'static>>, Interrupt> {
|
||||
vararg_element(ctx)
|
||||
}
|
||||
|
||||
|
||||
@@ -21,10 +21,10 @@ fn translate_footprint_extent(content: ExtentIn<'_>, _offset: ValueIn<'_, DVec2>
|
||||
|
||||
/// Constructs an artboard element with the given content and metadata stored as attributes.
|
||||
#[node_macro::node(category(""))]
|
||||
pub fn create_artboard(
|
||||
pub fn create_artboard<'e>(
|
||||
_: impl Ctx,
|
||||
/// Graphics to include within the artboard.
|
||||
content: IList<Graphic>,
|
||||
content: IList<Graphic<'e>>,
|
||||
/// Coordinate of the top-left corner of the artboard within the document.
|
||||
location: DVec2,
|
||||
/// Width and height of the artboard within the document.
|
||||
@@ -34,9 +34,8 @@ pub fn create_artboard(
|
||||
/// Whether to cut off the contained content that extends outside the artboard, or keep it visible.
|
||||
#[default(true)]
|
||||
clip: bool,
|
||||
) -> (Artboard, Attr<Location>, Attr<Dimensions>, Attr<Background>, Attr<Clip>) {
|
||||
// SAFETY: a materialized input's frames are arena-resident.
|
||||
let item = unsafe { core_types::record::GroupItem::from_resident(content.batch()) };
|
||||
) -> (Artboard<'e>, Attr<Location>, Attr<Dimensions>, Attr<Background>, Attr<Clip>) {
|
||||
let item = content.as_group_item();
|
||||
let content = core_types::list::List::new_from_element(Graphic::Group(core_types::record::Group {
|
||||
row: None,
|
||||
content: item,
|
||||
|
||||
@@ -212,7 +212,7 @@ where
|
||||
trace: Vec::new(),
|
||||
})
|
||||
};
|
||||
let park_paint = |paint: Option<List<Graphic>>| -> Result<Option<&'e List<Graphic>>, Interrupt> {
|
||||
let park_paint = |paint: Option<List<Graphic<'static>>>| -> Result<Option<&'e List<Graphic<'static>>>, Interrupt> {
|
||||
match paint {
|
||||
Some(paint) => Ok(Some(arena.alloc(paint).ok_or_else(exhausted)?.0)),
|
||||
None => Ok(None),
|
||||
@@ -243,16 +243,18 @@ where
|
||||
}
|
||||
|
||||
/// The materialized level as its legacy list, content kept native.
|
||||
fn legacy_render_list_of<T: Clone + Send + Sync + 'static>(content: core_types::node::List<'_, T>) -> List<T> {
|
||||
// SAFETY: a materialized input's frames are arena-resident.
|
||||
let item = unsafe { core_types::record::GroupItem::from_resident(content.batch()) };
|
||||
graphic_types::graphic::run_to_list::<T>(&item).expect("the run holds the row's element type")
|
||||
fn legacy_render_list_of<T: dyn_any::StaticTypeSized>(content: core_types::node::List<'_, T>) -> List<T::Static>
|
||||
where
|
||||
T::Static: Clone + Send + Sync + dyn_any::StaticTypeSized,
|
||||
{
|
||||
let item = content.as_group_item();
|
||||
graphic_types::graphic::run_to_list::<T::Static>(&item).expect("the run holds the row's element type")
|
||||
}
|
||||
|
||||
#[node_macro::node(category("General"), extent(mirror_extent))]
|
||||
fn mirror<'e>(
|
||||
ctx: impl Ctx + core_types::context::ExtractArena<'e> + ExtractIndex + InjectIndex + Copy,
|
||||
content: IList<Graphic>,
|
||||
content: IList<Graphic<'static>>,
|
||||
#[default(ReferencePoint::Center)] relative_to_bounds: ReferencePoint,
|
||||
#[unit(" px")] offset: f64,
|
||||
#[range]
|
||||
@@ -261,7 +263,7 @@ fn mirror<'e>(
|
||||
#[default(true)] keep_original: bool,
|
||||
) -> Result<
|
||||
IList<(
|
||||
Graphic,
|
||||
Graphic<'static>,
|
||||
Attr<'e, TransformAttr>,
|
||||
Attr<'e, graphic_types::markers::Fill>,
|
||||
Attr<'e, graphic_types::markers::Stroke>,
|
||||
@@ -454,12 +456,11 @@ pub fn legacy_layer_extend<T: Send + Clone>(
|
||||
/// lower a wrapped vector level to the bare typed graphic the pre-flip wrap made.
|
||||
/// The inverse of this node is 'Flatten Graphic'.
|
||||
#[node_macro::node(category("General"), extent(wrap_graphic_extent))]
|
||||
pub fn wrap_graphic<T: Clone + Send + Sync + core_types::CacheHash + 'static>(
|
||||
pub fn wrap_graphic<'e, T: Clone + Send + Sync + core_types::CacheHash + 'static>(
|
||||
_: impl Ctx,
|
||||
#[implementations(Graphic, Vector, Raster<CPU>, Raster<GPU>, Color, GradientStops, String)] content: IList<T>,
|
||||
) -> Result<IList<Graphic>, Interrupt> {
|
||||
// SAFETY: a materialized input's frames are arena-resident.
|
||||
let item = unsafe { core_types::record::GroupItem::from_resident(content.batch()) };
|
||||
) -> Result<IList<Graphic<'e>>, Interrupt> {
|
||||
let item = content.as_group_item();
|
||||
Ok(Graphic::Group(core_types::record::Group {
|
||||
row: None,
|
||||
content: item,
|
||||
@@ -476,8 +477,8 @@ fn wrap_graphic_extent<T>(_content: ListIn<'_, T>, _level: LevelIn) -> GPoll<Ext
|
||||
/// collapse (`to_graphic_typed` serves those rows). The legacy list rows accept an
|
||||
/// unconverted producer's list value as one element, built as a native group.
|
||||
#[node_macro::node(category("General"))]
|
||||
pub fn to_graphic<T: graphic_types::graphic::IntoGraphicElement>(
|
||||
ctx: impl Ctx + core_types::context::BorrowArena,
|
||||
pub fn to_graphic<'e, T: graphic_types::graphic::IntoGraphicElement>(
|
||||
ctx: impl Ctx + core_types::context::ExtractArena<'e>,
|
||||
#[implementations(
|
||||
Graphic,
|
||||
List<Graphic>,
|
||||
@@ -489,16 +490,16 @@ pub fn to_graphic<T: graphic_types::graphic::IntoGraphicElement>(
|
||||
List<String>,
|
||||
)]
|
||||
content: T,
|
||||
) -> Result<Graphic, Interrupt> {
|
||||
content.into_graphic_element(ctx.borrow_arena()).ok_or_else(|| GraphError::new("the arena is exhausted").into())
|
||||
) -> Result<Graphic<'e>, Interrupt> {
|
||||
content.into_graphic_element(ctx.arena()).ok_or_else(|| GraphError::new("the arena is exhausted").into())
|
||||
}
|
||||
|
||||
/// The elementwise `Graphic` coercion the compiler-inserted converts use: each
|
||||
/// lane's element converts on its own, so a typed wire feeds a graphic input
|
||||
/// without changing the level's shape. Registered under the convert identifier.
|
||||
#[node_macro::node(category(""))]
|
||||
pub fn to_graphic_element<T: graphic_types::graphic::IntoGraphicElement>(
|
||||
ctx: impl Ctx + core_types::context::BorrowArena,
|
||||
pub fn to_graphic_element<'e, T: graphic_types::graphic::IntoGraphicElement>(
|
||||
ctx: impl Ctx + core_types::context::ExtractArena<'e>,
|
||||
#[implementations(
|
||||
Graphic,
|
||||
Vector,
|
||||
@@ -516,20 +517,19 @@ pub fn to_graphic_element<T: graphic_types::graphic::IntoGraphicElement>(
|
||||
List<String>,
|
||||
)]
|
||||
content: T,
|
||||
) -> Result<Graphic, Interrupt> {
|
||||
content.into_graphic_element(ctx.borrow_arena()).ok_or_else(|| GraphError::new("the arena is exhausted").into())
|
||||
) -> Result<Graphic<'e>, Interrupt> {
|
||||
content.into_graphic_element(ctx.arena()).ok_or_else(|| GraphError::new("the arena is exhausted").into())
|
||||
}
|
||||
|
||||
/// The typed-level conversion: the whole level nests as one graphic lane, as
|
||||
/// the pre-flip `Into<Graphic>` list collapse did. Registered under the to
|
||||
/// graphic identifier.
|
||||
#[node_macro::node(category(""), extent(wrap_graphic_extent))]
|
||||
pub fn to_graphic_typed<T: Clone + Send + Sync + core_types::CacheHash + 'static>(
|
||||
pub fn to_graphic_typed<'e, T: Clone + Send + Sync + core_types::CacheHash + 'static>(
|
||||
_: impl Ctx,
|
||||
#[implementations(Vector, Raster<CPU>, Raster<GPU>, Color, GradientStops, String)] content: IList<T>,
|
||||
) -> Result<IList<Graphic>, Interrupt> {
|
||||
// SAFETY: a materialized input's frames are arena-resident.
|
||||
let item = unsafe { core_types::record::GroupItem::from_resident(content.batch()) };
|
||||
) -> Result<IList<Graphic<'e>>, Interrupt> {
|
||||
let item = content.as_group_item();
|
||||
Ok(Graphic::Group(core_types::record::Group {
|
||||
row: None,
|
||||
content: item,
|
||||
@@ -539,7 +539,7 @@ pub fn to_graphic_typed<T: Clone + Send + Sync + core_types::CacheHash + 'static
|
||||
/// An unconnected content input carries the unit, which renders as nothing like
|
||||
/// the pre-flip empty list. Registered under the to graphic identifier.
|
||||
#[node_macro::node(category(""), extent(to_graphic_unit_extent))]
|
||||
pub fn to_graphic_unit(_: impl Ctx, _content: ()) -> Result<IList<Graphic>, Interrupt> {
|
||||
pub fn to_graphic_unit(_: impl Ctx, _content: ()) -> Result<IList<Graphic<'static>>, Interrupt> {
|
||||
Err(core_types::gpoll::GraphError::past_end().into())
|
||||
}
|
||||
|
||||
@@ -552,13 +552,12 @@ fn to_graphic_unit_extent(_content: core_types::extent::ValueIn<'_, ()>, _level:
|
||||
/// reads and content kept in its native form. Registered under the legacy
|
||||
/// convert identifiers; the rows die with the last legacy consumer.
|
||||
#[node_macro::node(category(""))]
|
||||
pub fn level_to_list<T: Clone + Send + Sync + CacheHash + 'static>(
|
||||
pub fn level_to_list<T: Clone + Send + Sync + CacheHash + dyn_any::StaticTypeSized>(
|
||||
_: impl Ctx,
|
||||
#[implementations(Graphic, Vector, Raster<CPU>, Raster<GPU>, Color, GradientStops, String)] value: IList<T>,
|
||||
_converter: (),
|
||||
) -> List<T> {
|
||||
// SAFETY: a materialized input's frames are arena-resident.
|
||||
let item = unsafe { core_types::record::GroupItem::from_resident(value.batch()) };
|
||||
let item = value.as_group_item();
|
||||
graphic_types::graphic::run_to_list::<T>(&item).expect("the run holds the row's element type")
|
||||
}
|
||||
|
||||
@@ -569,7 +568,7 @@ pub use _to_graphic_unit_mod::to_graphic_unit_entries;
|
||||
|
||||
/// Removes a level of nesting from a `Graphic[]`, or all nesting if "Fully Flatten" is enabled.
|
||||
#[node_macro::node(category("General"), extent(flatten_graphic_extent))]
|
||||
pub fn flatten_graphic(ctx: impl Ctx + ExtractIndex + InjectIndex + Copy, content: IList<Graphic>, fully_flatten: bool) -> Result<IList<(Graphic, Attr<TransformAttr>)>, Interrupt> {
|
||||
pub fn flatten_graphic(ctx: impl Ctx + ExtractIndex + InjectIndex + Copy, content: IList<Graphic<'static>>, fully_flatten: bool) -> Result<IList<(Graphic<'static>, Attr<TransformAttr>)>, Interrupt> {
|
||||
let mut remaining = ctx.index() as usize;
|
||||
for row in 0..content.len() {
|
||||
let graphic = content.element_ref(row);
|
||||
|
||||
@@ -24,7 +24,7 @@ pub(crate) fn group_leaf_count(group: &core_types::record::Group, fully_flatten:
|
||||
(0..lanes.len()).map(|lane| leaf_count(lanes.element_ref(lane), fully_flatten, depth + 1)).sum()
|
||||
}
|
||||
|
||||
pub(crate) fn group_locate(group: &core_types::record::Group, transform: DAffine2, fully_flatten: bool, depth: usize, remaining: &mut usize) -> Option<(Graphic, DAffine2)> {
|
||||
pub(crate) fn group_locate<'e>(group: &core_types::record::Group<'e>, transform: DAffine2, fully_flatten: bool, depth: usize, remaining: &mut usize) -> Option<(Graphic<'e>, DAffine2)> {
|
||||
let item = &group.content;
|
||||
let lanes = item.typed_lanes::<Graphic>().expect("guarded by group_expands");
|
||||
let offset = item.layout().offset_of(ATTR_TRANSFORM, 0);
|
||||
@@ -50,7 +50,7 @@ pub(crate) fn leaf_count(graphic: &Graphic, fully_flatten: bool, depth: usize) -
|
||||
|
||||
/// The `remaining`-th leaf of `graphic` in walk order, with the transforms
|
||||
/// along its path composed onto `transform`.
|
||||
pub(crate) fn locate(graphic: &Graphic, transform: DAffine2, fully_flatten: bool, depth: usize, remaining: &mut usize) -> Option<(Graphic, DAffine2)> {
|
||||
pub(crate) fn locate<'e>(graphic: &Graphic<'e>, transform: DAffine2, fully_flatten: bool, depth: usize, remaining: &mut usize) -> Option<(Graphic<'e>, DAffine2)> {
|
||||
match graphic {
|
||||
Graphic::Graphic(children) if fully_flatten || depth == 0 => (0..children.len()).find_map(|index| {
|
||||
let child = children.element(index)?;
|
||||
@@ -70,7 +70,7 @@ pub(crate) fn locate(graphic: &Graphic, transform: DAffine2, fully_flatten: bool
|
||||
/// the transforms along its path composed; a group beyond the walk's depth
|
||||
/// rides as a leaf with its embedded transforms untouched.
|
||||
#[node_macro::node(category("Test"), extent(flatten_extent))]
|
||||
fn flatten(ctx: impl Ctx + ExtractIndex + InjectIndex + Copy, content: IList<Graphic>, fully_flatten: bool) -> Result<IList<(Graphic, Attr<Transform>)>, Interrupt> {
|
||||
fn flatten(ctx: impl Ctx + ExtractIndex + InjectIndex + Copy, content: IList<Graphic<'static>>, fully_flatten: bool) -> Result<IList<(Graphic<'static>, Attr<Transform>)>, Interrupt> {
|
||||
let mut remaining = ctx.index() as usize;
|
||||
for row in 0..content.len() {
|
||||
let graphic = content.element_ref(row);
|
||||
@@ -101,9 +101,8 @@ fn flatten_extent(content: ListIn<'_, Graphic>, fully_flatten: ValueIn<'_, bool>
|
||||
/// Rank-model Wrap: the content level as one group element on a one-lane
|
||||
/// level, the inverse of flatten's one-level descent.
|
||||
#[node_macro::node(category("Test"), extent(wrap_extent))]
|
||||
fn wrap(_: impl Ctx, content: IList<Graphic>) -> Result<IList<Graphic>, Interrupt> {
|
||||
// SAFETY: a materialized input's frames are arena-resident.
|
||||
let item = unsafe { core_types::record::GroupItem::from_resident(content.batch()) };
|
||||
fn wrap<'e>(_: impl Ctx, content: IList<Graphic<'e>>) -> Result<IList<Graphic<'e>>, Interrupt> {
|
||||
let item = content.as_group_item();
|
||||
Ok(Graphic::Group(core_types::record::Group {
|
||||
row: None,
|
||||
content: item,
|
||||
@@ -240,7 +239,7 @@ mod tests {
|
||||
|
||||
struct GraphicSource {
|
||||
layout: Layout,
|
||||
rows: Vec<(Graphic, DAffine2)>,
|
||||
rows: Vec<(Graphic<'static>, DAffine2)>,
|
||||
}
|
||||
|
||||
impl<'e> Node<ContextImpl<'e>> for GraphicSource {
|
||||
@@ -295,11 +294,11 @@ mod tests {
|
||||
Layout::default().with_writes(1, record::element_write_hashed::<Graphic>(), &[record::FieldWrite::of::<Transform>(0)])
|
||||
}
|
||||
|
||||
fn text(label: &str) -> Graphic {
|
||||
fn text(label: &str) -> Graphic<'static> {
|
||||
Graphic::Text(label.to_string())
|
||||
}
|
||||
|
||||
fn group(children: Vec<(Graphic, DAffine2)>) -> Graphic {
|
||||
fn group(children: Vec<(Graphic<'static>, DAffine2)>) -> Graphic {
|
||||
let mut list = List::new();
|
||||
for (index, (child, transform)) in children.into_iter().enumerate() {
|
||||
list.push(Item::new_from_element(child));
|
||||
@@ -308,7 +307,7 @@ mod tests {
|
||||
Graphic::Graphic(list)
|
||||
}
|
||||
|
||||
fn text_of(graphic: &Graphic) -> &str {
|
||||
fn text_of<'a>(graphic: &'a Graphic<'_>) -> &'a str {
|
||||
let Graphic::Text(text) = graphic else {
|
||||
panic!("expected a text leaf, got {graphic:?}");
|
||||
};
|
||||
@@ -321,7 +320,7 @@ mod tests {
|
||||
|
||||
/// [a, G[b, H[c]]] with translations picked so each composed path is a
|
||||
/// distinct sum.
|
||||
fn fixture_rows() -> Vec<(Graphic, DAffine2)> {
|
||||
fn fixture_rows() -> Vec<(Graphic<'static>, DAffine2)> {
|
||||
vec![
|
||||
(text("a"), translation(1.)),
|
||||
(
|
||||
@@ -395,7 +394,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn ragged_rows() -> Vec<(Graphic, DAffine2)> {
|
||||
fn ragged_rows() -> Vec<(Graphic<'static>, DAffine2)> {
|
||||
vec![(text("ab"), translation(10.)), (text("xyz"), translation(20.))]
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ fn intermediate_of<R: Render>(data: &R, render_params: &RenderParams) -> RenderI
|
||||
}
|
||||
|
||||
#[node_macro::node(category(""))]
|
||||
fn render_intermediate<T: 'static + Render + WasmNotSend + Send + Sync>(
|
||||
fn render_intermediate<T: dyn_any::StaticTypeSized + 'static + Render + WasmNotSend + Send + Sync>(
|
||||
ctx: impl Ctx + ExtractVarArgs + DeriveCtx,
|
||||
#[implementations(
|
||||
Context -> List<Artboard>,
|
||||
@@ -78,15 +78,14 @@ fn render_intermediate<T: 'static + Render + WasmNotSend + Send + Sync>(
|
||||
/// The leveled form of `render_intermediate`: the wire's records materialize
|
||||
/// into a run, which renders directly.
|
||||
#[node_macro::node(category(""))]
|
||||
fn render_intermediate_leveled<T: Clone + Send + Sync + core_types::CacheHash + 'static>(
|
||||
fn render_intermediate_leveled<T: Clone + Send + Sync + core_types::CacheHash + dyn_any::StaticTypeSized + 'static>(
|
||||
ctx: impl Ctx + ExtractVarArgs + ExtractIndex + InjectIndex + Copy,
|
||||
#[implementations(Artboard, Graphic, Vector, Raster<CPU>, Color, GradientStops, String)] data: IList<T>,
|
||||
) -> Result<RenderIntermediate, Interrupt>
|
||||
where
|
||||
for<'a> core_types::record::RunView<'a, T>: Render,
|
||||
{
|
||||
// SAFETY: a materialized input's frames are arena-resident.
|
||||
let item = unsafe { core_types::record::GroupItem::from_resident(data.batch()) };
|
||||
let item = data.as_group_item();
|
||||
let run = core_types::record::RunView::<T>::new(&item).expect("the run holds the row's element type");
|
||||
let render_params = ctx
|
||||
.vararg(0)
|
||||
|
||||
@@ -3,7 +3,7 @@ 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_OPACITY, ATTR_OPACITY_FILL, ATTR_TRANSFORM, BlendMode, Color, Ctx};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphic_types::graphic::{GraphicLevel, PaintColumns, PaintReach, bake_paint_transforms, set_paint_attribute, set_paint_attribute_at};
|
||||
use graphic_types::graphic::{GraphicLevel, PaintColumns, PaintReach, bake_paint_transforms, is_paint_present, set_paint_attribute, set_paint_attribute_at};
|
||||
use graphic_types::raster_types::{CPU, GPU, Raster};
|
||||
use graphic_types::vector_types::GradientStops;
|
||||
use graphic_types::markers::{EditorMergedLayers, Fill, Stroke};
|
||||
@@ -27,7 +27,7 @@ pub use vector_types::vector::misc::BooleanOperation;
|
||||
fn boolean_core<'e>(
|
||||
arena: &'e core_types::arena::Arena,
|
||||
flattened: List<Vector>,
|
||||
snapshot: List<Graphic>,
|
||||
snapshot: List<Graphic<'static>>,
|
||||
operation: BooleanOperation,
|
||||
) -> Result<
|
||||
(
|
||||
@@ -67,7 +67,7 @@ fn boolean_core<'e>(
|
||||
trace: Vec::new(),
|
||||
})
|
||||
};
|
||||
let park_paint = |paint: Option<List<Graphic>>| -> Result<Option<&'e List<Graphic>>, core_types::gpoll::Interrupt> {
|
||||
let park_paint = |paint: Option<List<Graphic<'static>>>| -> Result<Option<&'e List<Graphic>>, core_types::gpoll::Interrupt> {
|
||||
match paint {
|
||||
Some(list) => Ok(Some(arena.alloc(list).ok_or_else(exhausted)?.0)),
|
||||
None => Ok(None),
|
||||
@@ -75,8 +75,9 @@ fn boolean_core<'e>(
|
||||
};
|
||||
|
||||
let element = result_vector_list.element(0).cloned().unwrap_or_default();
|
||||
let fill = park_paint(graphic_types::graphic::paint_graphics::<Fill, _>(&result_vector_list, 0).cloned())?;
|
||||
let stroke = park_paint(graphic_types::graphic::paint_graphics::<Stroke, _>(&result_vector_list, 0).cloned())?;
|
||||
use core_types::lane::LaneSource;
|
||||
let fill = park_paint(result_vector_list.attr::<Fill>(0).filter(|paint| is_paint_present(paint)).cloned())?;
|
||||
let stroke = park_paint(result_vector_list.attr::<Stroke>(0).filter(|paint| is_paint_present(paint)).cloned())?;
|
||||
let layer_path: Vec<NodeId> = result_vector_list.attribute::<Vec<NodeId>>(ATTR_EDITOR_LAYER_PATH, 0).map(|path| path.clone()).unwrap_or_default();
|
||||
let layer_path = arena.alloc(layer_path).ok_or_else(exhausted)?.0;
|
||||
// Snapshot the input layers so the renderer can recurse into them for
|
||||
@@ -102,7 +103,7 @@ fn boolean_core<'e>(
|
||||
fn boolean_operation<'e>(
|
||||
ctx: impl Ctx + ExtractArena<'e> + core_types::InjectIndex + Copy,
|
||||
/// The wire of vector paths to perform the boolean operation on. Nested groups are automatically flattened.
|
||||
content: IList<Graphic>,
|
||||
content: IList<Graphic<'static>>,
|
||||
/// Which boolean operation to perform on the paths.
|
||||
///
|
||||
/// Union combines all paths while cutting out overlapping areas (even the interiors of a single path).
|
||||
@@ -125,8 +126,7 @@ fn boolean_operation<'e>(
|
||||
),
|
||||
core_types::gpoll::Interrupt,
|
||||
> {
|
||||
// SAFETY: a materialized input's frames are arena-resident.
|
||||
let item = unsafe { core_types::record::GroupItem::from_resident(content.batch()) };
|
||||
let item = content.as_group_item();
|
||||
let flattened = flatten_vector_run(GraphicLevel::Run(&item), DAffine2::IDENTITY, PaintReach::NONE);
|
||||
let snapshot = graphic_types::graphic::run_to_list::<Graphic>(&item)
|
||||
.expect("the run holds the row's element type")
|
||||
@@ -155,8 +155,7 @@ fn boolean_operation_vector<'e>(
|
||||
),
|
||||
core_types::gpoll::Interrupt,
|
||||
> {
|
||||
// SAFETY: a materialized input's frames are arena-resident.
|
||||
let item = unsafe { core_types::record::GroupItem::from_resident(content.batch()) };
|
||||
let item = content.as_group_item();
|
||||
let flattened = graphic_types::graphic::run_to_list::<Vector>(&item).expect("the run holds vector lanes");
|
||||
let snapshot = graphic_types::graphic::run_to_list::<Vector>(&item)
|
||||
.expect("the run holds the row's element type")
|
||||
@@ -555,7 +554,7 @@ mod tests {
|
||||
Vector::from_subpath(Subpath::<PointId>::new_rectangle(corner, corner + DVec2::ONE))
|
||||
}
|
||||
|
||||
fn black_paint() -> List<Graphic> {
|
||||
fn black_paint() -> List<Graphic<'static>> {
|
||||
List::new_from_element(Graphic::Color(Color::BLACK))
|
||||
}
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ fn assign_colors<'e>(
|
||||
return Err(GraphError::past_end().into());
|
||||
}
|
||||
let element = content.element_ref(lane).clone();
|
||||
let park_existing = |paint: Option<&List<Graphic>>| -> Result<Option<&'e List<Graphic>>, Interrupt> { paint.map(|paint| park_paint(ctx.arena(), paint.clone())).transpose() };
|
||||
let park_existing = |paint: Option<&List<Graphic<'static>>>| -> Result<Option<&'e List<Graphic>>, Interrupt> { paint.map(|paint| park_paint(ctx.arena(), paint.clone())).transpose() };
|
||||
let existing_fill = park_existing(content.lane(lane).attr::<Fill>())?;
|
||||
let existing_stroke = park_existing(content.lane(lane).attr::<StrokeAttr>())?;
|
||||
let carried = carried_lane_attrs(ctx.arena(), *content.lane(lane))?;
|
||||
@@ -164,7 +164,7 @@ fn assign_colors_extent(
|
||||
#[node_macro::node(category(""), extent(assign_colors_graphic_extent))]
|
||||
fn assign_colors_graphic<'e>(
|
||||
ctx: impl Ctx + CacheHash + ExtractArena<'e> + ExtractIndex + InjectIndex + Copy,
|
||||
content: IList<Graphic>,
|
||||
content: IList<Graphic<'static>>,
|
||||
#[data] lane_offsets: std::sync::Arc<std::sync::Mutex<Option<LaneOffsets>>>,
|
||||
#[default(true)] fill: bool,
|
||||
stroke: bool,
|
||||
@@ -173,7 +173,7 @@ fn assign_colors_graphic<'e>(
|
||||
randomize: bool,
|
||||
seed: SeedValue,
|
||||
repeat_every: u32,
|
||||
) -> Result<IList<(Graphic, Attr<'e, TransformAttr>, Attr<'e, EditorLayerPath>)>, Interrupt> {
|
||||
) -> Result<IList<(Graphic<'e>, Attr<'e, TransformAttr>, Attr<'e, EditorLayerPath>)>, Interrupt> {
|
||||
let lane = ctx.index() as usize;
|
||||
if lane >= content.len() {
|
||||
return Err(GraphError::past_end().into());
|
||||
@@ -276,7 +276,7 @@ fn assign_colors_graphic_extent(
|
||||
|
||||
pub use _assign_colors_graphic_mod::assign_colors_graphic_entries;
|
||||
|
||||
fn park_paint(arena: &core_types::arena::Arena, paint: List<Graphic>) -> Result<&List<Graphic>, Interrupt> {
|
||||
fn park_paint<'e>(arena: &'e core_types::arena::Arena, paint: List<Graphic<'static>>) -> Result<&'e List<Graphic<'static>>, Interrupt> {
|
||||
let (parked, _) = arena.alloc(paint).ok_or(GraphError {
|
||||
kind: core_types::gpoll::ErrorKind::ArenaExhausted,
|
||||
trace: Vec::new(),
|
||||
@@ -319,9 +319,8 @@ fn default_gradient_paint(paint: &mut List<Graphic>, bounds: Option<[DVec2; 2]>,
|
||||
|
||||
/// The materialized paint level as the canonical owned paint list, content
|
||||
/// kept in its native form.
|
||||
fn paint_table(paint: core_types::node::List<'_, Graphic>) -> List<Graphic> {
|
||||
// SAFETY: a materialized input's frames are arena-resident.
|
||||
let item = unsafe { core_types::record::GroupItem::from_resident(paint.batch()) };
|
||||
fn paint_table(paint: core_types::node::List<'_, Graphic<'_>>) -> List<Graphic<'static>> {
|
||||
let item = paint.as_group_item();
|
||||
graphic_types::graphic::run_to_list::<Graphic>(&item).expect("a paint level holds graphic lanes")
|
||||
}
|
||||
|
||||
@@ -331,10 +330,10 @@ fn paint_table(paint: core_types::node::List<'_, Graphic>) -> List<Graphic> {
|
||||
fn fill<'e>(
|
||||
ctx: impl Ctx + ExtractArena<'e> + ExtractIndex + InjectIndex + Copy,
|
||||
/// The content with vector paths to apply the fill style to.
|
||||
(element, _content_fill): (Vector, Attr<'e, Fill>),
|
||||
(element, _content_fill): (Vector, Attr<Fill>),
|
||||
/// The fill to paint the path with.
|
||||
#[default(Color::BLACK)]
|
||||
fill: IList<Graphic>,
|
||||
fill: IList<Graphic<'static>>,
|
||||
_backup_color: IList<Color>,
|
||||
_backup_gradient: IList<GradientStops>,
|
||||
_gradient_type: GradientType,
|
||||
@@ -353,14 +352,14 @@ fn fill<'e>(
|
||||
#[node_macro::node(category(""))]
|
||||
fn fill_graphic_leveled<'e>(
|
||||
ctx: impl Ctx + ExtractArena<'e> + ExtractIndex + InjectIndex + Copy,
|
||||
(element, _content_fill): (Graphic, Attr<'e, Fill>),
|
||||
#[default(Color::BLACK)] fill: IList<Graphic>,
|
||||
(element, _content_fill): (Graphic<'static>, Attr<Fill>),
|
||||
#[default(Color::BLACK)] fill: IList<Graphic<'static>>,
|
||||
_backup_color: IList<Color>,
|
||||
_backup_gradient: IList<GradientStops>,
|
||||
_gradient_type: GradientType,
|
||||
_spread_method: GradientSpreadMethod,
|
||||
_transform: Option<DAffine2>,
|
||||
) -> Result<(Graphic, Attr<'e, Fill>), Interrupt> {
|
||||
) -> Result<(Graphic<'static>, Attr<'e, Fill>), Interrupt> {
|
||||
let bounds = match BoundingBox::bounding_box(&element, DAffine2::IDENTITY, false) {
|
||||
RenderBoundingBox::Rectangle(bounds) => Some(bounds),
|
||||
_ => None,
|
||||
@@ -379,7 +378,7 @@ fn stroke<'e>(
|
||||
(element, content_transform): (Vector, Attr<TransformAttr>),
|
||||
/// The stroke paint.
|
||||
#[default(Color::BLACK)]
|
||||
paint: IList<Graphic>,
|
||||
paint: IList<Graphic<'static>>,
|
||||
/// The stroke thickness.
|
||||
#[unit(" px")]
|
||||
#[default(2.)]
|
||||
@@ -446,8 +445,8 @@ fn for_each_interior_vector_mut(element: &mut Graphic, mut f: impl FnMut(&mut Ve
|
||||
#[node_macro::node(category(""))]
|
||||
fn stroke_graphic_leveled<'e>(
|
||||
ctx: impl Ctx + ExtractArena<'e> + ExtractIndex + InjectIndex + Copy,
|
||||
(element, content_transform): (Graphic, Attr<TransformAttr>),
|
||||
#[default(Color::BLACK)] paint: IList<Graphic>,
|
||||
(element, content_transform): (Graphic<'static>, Attr<TransformAttr>),
|
||||
#[default(Color::BLACK)] paint: IList<Graphic<'static>>,
|
||||
#[unit(" px")]
|
||||
#[default(2.)]
|
||||
weight: f64,
|
||||
@@ -458,7 +457,7 @@ fn stroke_graphic_leveled<'e>(
|
||||
paint_order: PaintOrder,
|
||||
dash_lengths: IList<f64>,
|
||||
#[unit(" px")] dash_offset: f64,
|
||||
) -> Result<(Graphic, Attr<TransformAttr>, Attr<'e, StrokeAttr>), Interrupt> {
|
||||
) -> Result<(Graphic<'static>, Attr<TransformAttr>, Attr<'e, StrokeAttr>), Interrupt> {
|
||||
let dash_lengths = (0..dash_lengths.len()).map(|index| dash_lengths.get(index).max(0.)).collect();
|
||||
let stroke = Stroke {
|
||||
weight,
|
||||
@@ -1453,7 +1452,7 @@ fn solidify_rows(flattened: List<Vector>) -> List<Vector> {
|
||||
fn solidify_native_lane<'e>(
|
||||
arena: &'e core_types::arena::Arena,
|
||||
level: graphic_types::graphic::GraphicLevel<'_>,
|
||||
snapshot: impl FnOnce() -> List<Graphic>,
|
||||
snapshot: impl FnOnce() -> List<Graphic<'static>>,
|
||||
lane: usize,
|
||||
) -> Result<
|
||||
(
|
||||
@@ -1575,9 +1574,8 @@ fn emit_legacy_lane<'e>(
|
||||
|
||||
/// The wrap the legacy list collapse applied to a vector level: the run as
|
||||
/// one group lane, lane 0's layer path stamped on the wrapper.
|
||||
fn wrap_vector_level(content: core_types::node::List<'_, Vector>) -> List<Graphic> {
|
||||
// SAFETY: a materialized input's frames are arena-resident.
|
||||
let item = unsafe { core_types::record::GroupItem::from_resident(content.batch()) };
|
||||
fn wrap_vector_level(content: core_types::node::List<'_, Vector>) -> List<Graphic<'_>> {
|
||||
let item = content.as_group_item();
|
||||
let layer_path: Vec<NodeId> = match content.len() > 0 {
|
||||
true => content.lane(0).attr::<EditorLayerPath>().to_vec(),
|
||||
false => Vec::new(),
|
||||
@@ -1591,13 +1589,13 @@ fn wrap_vector_level(content: core_types::node::List<'_, Vector>) -> List<Graphi
|
||||
|
||||
/// The materialized level as the legacy graphic list the editor-facing
|
||||
/// merged-layers snapshots carry.
|
||||
fn legacy_graphic_list_of<T: Clone + Send + Sync + 'static>(content: core_types::node::List<'_, T>) -> List<Graphic>
|
||||
fn legacy_graphic_list_of<T: dyn_any::StaticTypeSized>(content: core_types::node::List<'_, T>) -> List<Graphic<'static>>
|
||||
where
|
||||
List<T>: IntoGraphicList,
|
||||
T::Static: Clone + Send + Sync + dyn_any::StaticTypeSized,
|
||||
List<T::Static>: IntoGraphicList,
|
||||
{
|
||||
// SAFETY: a materialized input's frames are arena-resident.
|
||||
let item = unsafe { core_types::record::GroupItem::from_resident(content.batch()) };
|
||||
graphic_types::graphic::run_to_list::<T>(&item)
|
||||
let item = content.as_group_item();
|
||||
graphic_types::graphic::run_to_list::<T::Static>(&item)
|
||||
.expect("the run holds the row's element type")
|
||||
.into_graphic_list()
|
||||
}
|
||||
@@ -1605,7 +1603,7 @@ where
|
||||
#[node_macro::node(category("Vector: Modifier"), path(core_types::vector), extent(solidify_stroke_extent))]
|
||||
fn solidify_stroke<'e>(
|
||||
ctx: impl Ctx + ExtractArena<'e> + ExtractIndex + InjectIndex + Copy,
|
||||
content: IList<Graphic>,
|
||||
content: IList<Graphic<'static>>,
|
||||
) -> Result<
|
||||
IList<(
|
||||
Vector,
|
||||
@@ -1621,8 +1619,7 @@ fn solidify_stroke<'e>(
|
||||
)>,
|
||||
Interrupt,
|
||||
> {
|
||||
// SAFETY: a materialized input's frames are arena-resident.
|
||||
let item = unsafe { core_types::record::GroupItem::from_resident(content.batch()) };
|
||||
let item = content.as_group_item();
|
||||
solidify_native_lane(ctx.arena(), graphic_types::graphic::GraphicLevel::Run(&item), || legacy_graphic_list_of(content), ctx.index() as usize)
|
||||
}
|
||||
|
||||
@@ -1812,7 +1809,7 @@ fn map_points_extent(content: ListIn<'_, Vector>, _mapped: ExtentIn<'_>, level:
|
||||
fn flatten_path_core<'e>(
|
||||
arena: &'e core_types::arena::Arena,
|
||||
flattened: List<Vector>,
|
||||
snapshot: List<Graphic>,
|
||||
snapshot: List<Graphic<'static>>,
|
||||
) -> Result<
|
||||
(
|
||||
Vector,
|
||||
@@ -1891,7 +1888,7 @@ fn flatten_path_core<'e>(
|
||||
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
|
||||
pub fn flatten_path<'e>(
|
||||
ctx: impl Ctx + ExtractArena<'e> + ExtractIndex + InjectIndex + Copy,
|
||||
content: IList<Graphic>,
|
||||
content: IList<Graphic<'static>>,
|
||||
) -> Result<
|
||||
(
|
||||
Vector,
|
||||
@@ -1903,8 +1900,7 @@ pub fn flatten_path<'e>(
|
||||
),
|
||||
Interrupt,
|
||||
> {
|
||||
// SAFETY: a materialized input's frames are arena-resident.
|
||||
let item = unsafe { core_types::record::GroupItem::from_resident(content.batch()) };
|
||||
let item = content.as_group_item();
|
||||
let flattened = graphic_types::graphic::flatten_vector_rows(graphic_types::graphic::GraphicLevel::Run(&item));
|
||||
let snapshot = graphic_types::graphic::run_to_list::<Graphic>(&item).expect("the run holds the row's element type");
|
||||
flatten_path_core(ctx.arena(), flattened, snapshot)
|
||||
@@ -2176,8 +2172,7 @@ fn decimate(
|
||||
/// The materialized vector level as the owned rows the cross-lane cores walk,
|
||||
/// content kept native.
|
||||
fn vector_rows_of(content: core_types::node::List<'_, Vector>) -> List<Vector> {
|
||||
// SAFETY: a materialized input's frames are arena-resident.
|
||||
let item = unsafe { core_types::record::GroupItem::from_resident(content.batch()) };
|
||||
let item = content.as_group_item();
|
||||
graphic_types::graphic::run_to_list::<Vector>(&item).expect("the run holds vector lanes")
|
||||
}
|
||||
|
||||
@@ -2625,7 +2620,8 @@ fn offset_points(
|
||||
/// Interpolates the geometry, appearance, and transform between multiple vector layers, producing a single morphed vector shape.
|
||||
///
|
||||
/// *Progression* morphs through all objects. Interpolation is linear unless *Path* geometry is provided to control the trajectory between key objects. The **Origins to Polyline** node may be used to create a path with anchor points corresponding to each object. Other nodes can modify its path segments.
|
||||
fn morph_core(flattened: List<Vector>, snapshot: List<Graphic>, progression: f64, reverse: bool, distribution: InterpolationDistribution, path: List<Vector>) -> List<Vector> {
|
||||
fn morph_core(flattened: List<Vector>, snapshot: List<Graphic<'static>>, progression: f64, reverse: bool, distribution: InterpolationDistribution, path: List<Vector>) -> List<Vector> {
|
||||
use core_types::lane::LaneSource;
|
||||
/// Promotes a segment's handle pair to cubic-equivalent Bézier control points.
|
||||
/// For linear segments (both None), handles are placed at their respective anchors (zero-length)
|
||||
/// so that interpolation against another zero-length cubic doesn't introduce unwanted curvature.
|
||||
@@ -2740,7 +2736,7 @@ fn morph_core(flattened: List<Vector>, snapshot: List<Graphic>, progression: f64
|
||||
}
|
||||
|
||||
// Lerp between two graphics. Solid color and gradient pairings interpolate; all other pairings step at the midpoint.
|
||||
fn lerp_graphic(a: Option<&List<Graphic>>, b: Option<&List<Graphic>>, time: f64) -> Option<List<Graphic>> {
|
||||
fn lerp_graphic(a: Option<&List<Graphic<'static>>>, b: Option<&List<Graphic<'static>>>, time: f64) -> Option<List<Graphic<'static>>> {
|
||||
let transparent = List::new_from_element(Color::TRANSPARENT).into_graphic_list();
|
||||
|
||||
let a = a.filter(|graphic_list| is_paint_present(graphic_list));
|
||||
@@ -3064,13 +3060,13 @@ fn morph_core(flattened: List<Vector>, snapshot: List<Graphic>, progression: f64
|
||||
let mut vector = Vector { stroke, ..Default::default() };
|
||||
|
||||
let fill_paint = {
|
||||
let source = paint_graphics::<Fill, _>(&content, source_index);
|
||||
let target = paint_graphics::<Fill, _>(&content, target_index);
|
||||
let source = content.attr::<Fill>(source_index).filter(|paint| is_paint_present(paint));
|
||||
let target = content.attr::<Fill>(target_index).filter(|paint| is_paint_present(paint));
|
||||
lerp_graphic(source, target, time)
|
||||
};
|
||||
let stroke_paint = {
|
||||
let source = paint_graphics::<StrokeAttr, _>(&content, source_index);
|
||||
let target = paint_graphics::<StrokeAttr, _>(&content, target_index);
|
||||
let source = content.attr::<StrokeAttr>(source_index).filter(|paint| is_paint_present(paint));
|
||||
let target = content.attr::<StrokeAttr>(target_index).filter(|paint| is_paint_present(paint));
|
||||
lerp_graphic(source, target, time)
|
||||
};
|
||||
|
||||
@@ -3247,7 +3243,7 @@ fn morph_core(flattened: List<Vector>, snapshot: List<Graphic>, progression: f64
|
||||
fn morph_lane<'e>(
|
||||
arena: &'e core_types::arena::Arena,
|
||||
flattened: List<Vector>,
|
||||
snapshot: List<Graphic>,
|
||||
snapshot: List<Graphic<'static>>,
|
||||
progression: f64,
|
||||
reverse: bool,
|
||||
distribution: InterpolationDistribution,
|
||||
@@ -3281,7 +3277,7 @@ fn morph_lane<'e>(
|
||||
fn morph<'e>(
|
||||
ctx: impl Ctx + ExtractArena<'e> + ExtractIndex + InjectIndex + Copy,
|
||||
/// The vector objects to interpolate between. Mixed graphic content is deeply flattened to keep only vector elements.
|
||||
content: IList<Graphic>,
|
||||
content: IList<Graphic<'static>>,
|
||||
/// The fractional part `[0, 1)` traverses the morph uniformly along the path. If the control path has multiple subpaths, each added integer selects the next subpath.
|
||||
progression: Progression,
|
||||
/// Swap the direction of the progression between objects or along the control path.
|
||||
@@ -3307,11 +3303,9 @@ fn morph<'e>(
|
||||
),
|
||||
Interrupt,
|
||||
> {
|
||||
// SAFETY: a materialized input's frames are arena-resident.
|
||||
let path_item = unsafe { core_types::record::GroupItem::from_resident(path.batch()) };
|
||||
let path_item = path.as_group_item();
|
||||
let path = graphic_types::graphic::run_to_list::<Vector>(&path_item).expect("the run holds vector lanes");
|
||||
// SAFETY: a materialized input's frames are arena-resident.
|
||||
let item = unsafe { core_types::record::GroupItem::from_resident(content.batch()) };
|
||||
let item = content.as_group_item();
|
||||
let flattened = graphic_types::graphic::flatten_vector_rows(graphic_types::graphic::GraphicLevel::Run(&item));
|
||||
morph_lane(ctx.arena(), flattened, legacy_graphic_list_of(content), progression, reverse, distribution, path)
|
||||
}
|
||||
@@ -3341,8 +3335,7 @@ fn morph_vector<'e>(
|
||||
),
|
||||
Interrupt,
|
||||
> {
|
||||
// SAFETY: a materialized input's frames are arena-resident.
|
||||
let path_item = unsafe { core_types::record::GroupItem::from_resident(path.batch()) };
|
||||
let path_item = path.as_group_item();
|
||||
let path = graphic_types::graphic::run_to_list::<Vector>(&path_item).expect("the run holds vector lanes");
|
||||
let wrapper = wrap_vector_level(content);
|
||||
let flattened = graphic_types::graphic::flatten_vector_rows(graphic_types::graphic::GraphicLevel::Legacy(&wrapper));
|
||||
|
||||
Reference in New Issue
Block a user