Store artboard content as a native group

This commit is contained in:
Dennis Kobert
2026-08-26 21:50:36 +00:00
parent 7d44f6ec9e
commit ed457093b1
3 changed files with 47 additions and 3 deletions

View File

@@ -30,8 +30,43 @@ impl Artboard {
pub fn into_graphic_list(self) -> List<Graphic> {
self.0
}
/// The artboard with every content group converted to its legacy form, so
/// the value owns all of its content free of arena borrows.
pub fn with_legacy_groups(&self) -> Artboard {
let mut content = self.0.clone();
for element in content.iter_element_values_mut() {
*element = crate::graphic::map_groups_to_legacy(element);
}
Artboard(content)
}
}
/// The deep clone-out for `Artboard` elements: as for `Graphic`, a plain
/// clone of group content would carry frame pointers into the evaluation's
/// arena, so memo and capture seams copy out the legacy-converted form.
///
/// # Safety
/// `ptr` must point at a live parked `Artboard` element field.
unsafe fn deep_clone_artboard(ptr: *const u8) -> Box<dyn std::any::Any + Send + Sync> {
let artboard = unsafe { core_types::record::borrow_element::<Artboard>(core_types::record::Rec::new(ptr)) };
Box::new(artboard.with_legacy_groups())
}
const _: () = {
#[cfg(not(target_family = "wasm"))]
#[core_types::ctor::ctor]
fn register() {
core_types::record::register_deep_element_clone::<Artboard>(deep_clone_artboard);
}
#[cfg(target_family = "wasm")]
#[unsafe(export_name = "__node_registry_deep_element_artboard")]
extern "C" fn register() {
core_types::record::register_deep_element_clone::<Artboard>(deep_clone_artboard);
}
};
impl From<List<Graphic>> for Artboard {
fn from(content: List<Graphic>) -> Self {
Self(content)

View File

@@ -68,7 +68,16 @@ pub fn capture_to_legacy(capture: &RecordCapture, arena: &Arena) -> Option<Box<d
};
return Some(Box::new(group_to_legacy_list(&group)));
}
None.or_else(|| typed::<Artboard>(&item))
fn typed_artboards(item: &GroupItem) -> Option<Box<dyn std::any::Any + Send + Sync>> {
let mut list = run_to_legacy_list::<Artboard>(item)?;
// The capture outlives the arena generation, so group content must
// leave in its owned legacy form.
for artboard in list.iter_element_values_mut() {
*artboard = artboard.with_legacy_groups();
}
Some(Box::new(list))
}
None.or_else(|| typed_artboards(&item))
.or_else(|| typed::<Vector>(&item))
.or_else(|| typed::<Raster<CPU>>(&item))
.or_else(|| typed::<Raster<GPU>>(&item))

View File

@@ -37,10 +37,10 @@ pub fn create_artboard(
) -> (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()) };
let content = graphic_types::graphic::group_to_legacy_list(&core_types::record::Group {
let content = core_types::list::List::new_from_element(Graphic::Group(core_types::record::Group {
row: None,
content: core_types::record::GroupContent::Run(item),
});
}));
// Normalize so `location` is the top-left corner and `dimensions` are positive (allowing negative input
// dimensions to represent dragging from the opposite corner). Compute the corner using the raw signed