mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Drop the manual extent overrides in favor of the derivation
This commit is contained in:
@@ -200,16 +200,26 @@ pub fn is_paint_present(graphic_list: &List<Graphic>) -> bool {
|
||||
|
||||
/// Look up the paint graphics stored under attribute for a vector item, in the canonical `List<Graphic>` form.
|
||||
pub fn graphic_list_at<'a>(list: &'a List<Vector>, index: usize, attribute: &str) -> Option<Cow<'a, List<Graphic>>> {
|
||||
list.attribute::<List<Graphic>>(attribute, index)
|
||||
paint_at(list, index, attribute)
|
||||
.map(Cow::Borrowed)
|
||||
// Treat a blank paint attribute as absent so an empty attribute doesn't count as painted
|
||||
.filter(|graphic_list| is_paint_present(graphic_list))
|
||||
}
|
||||
|
||||
/// The paint attribute's list, in either transitional storage form: the
|
||||
/// canonical `List<Graphic>` value, or the fill marker's owned
|
||||
/// `Option<List<Graphic>>` clone as the render bridge copies it.
|
||||
fn paint_at<'a, T>(list: &'a List<T>, index: usize, attribute: &str) -> Option<&'a List<Graphic>> {
|
||||
if let Some(graphic_list) = list.attribute::<List<Graphic>>(attribute, index) {
|
||||
return Some(graphic_list);
|
||||
}
|
||||
list.attribute::<Option<List<Graphic>>>(attribute, index).and_then(|optional| optional.as_ref())
|
||||
}
|
||||
|
||||
/// Whether the item carries a non-blank canonical `List<Graphic>` paint attribute,
|
||||
/// checked by borrowing without cloning the renderable list.
|
||||
pub fn has_paint_at(list: &List<Vector>, index: usize, attribute: &str) -> bool {
|
||||
list.attribute::<List<Graphic>>(attribute, index).is_some_and(is_paint_present)
|
||||
paint_at(list, index, attribute).is_some_and(is_paint_present)
|
||||
}
|
||||
|
||||
/// Stores a paint attribute in its canonical `List<Graphic>` form, the only representation paint readers accept.
|
||||
|
||||
@@ -1442,11 +1442,32 @@ pub(crate) fn generate_node_impl(crate_ident: &CrateIdent, parsed: &ParsedNodeFn
|
||||
}
|
||||
}
|
||||
} else if let Some(subject_index) = ir::forwarded_subject(&node).filter(|_| node.output.shape.depth == 0) {
|
||||
// A level-preserving passthrough forwards its subject's extents.
|
||||
let name = ®ular_fields[subject_index].pat_ident.ident;
|
||||
// A level-preserving passthrough forwards its subject's extents,
|
||||
// through the same per-binding query forms the explicit surface uses.
|
||||
let field = ®ular_fields[subject_index];
|
||||
let name = &field.pat_ident.ident;
|
||||
let query = match &field.ty {
|
||||
ParsedFieldType::Node(_) => match ir::lazy_binding(&node, subject_index) {
|
||||
ir::LazyBinding::DeriveRouting | ir::LazyBinding::DeriveCarrier => quote! {
|
||||
let __query = |__copy: u64, __lvl: u8| {
|
||||
let __head = #core_types::context::DeriveCtx::index_head(__input);
|
||||
#core_types::record::DerivedRecordEdge::extent_at_derived(&self.#name, &#core_types::context::DeriveCtx::promoted(__input, &__head, __copy), __lvl)
|
||||
};
|
||||
},
|
||||
_ => quote! {
|
||||
let __query = |_: u64, __lvl: u8| #core_types::node::Node::extent_at(&self.#name, __input, __lvl);
|
||||
},
|
||||
},
|
||||
ParsedFieldType::Regular(_) => quote! {
|
||||
let __query = |_: u64, __lvl: u8| #core_types::node::Node::extent_at(&self.#name, __input, __lvl);
|
||||
},
|
||||
};
|
||||
quote! {
|
||||
fn extent_at(&self, __input: &#ctx_ident, __level: u8) -> #core_types::gpoll::GPoll<#core_types::gpoll::Extent> {
|
||||
#core_types::node::Node::extent_at(&self.#name, __input, __level)
|
||||
#query
|
||||
let __arg = #core_types::extent::ExtentIn::new(&__query);
|
||||
let __level_in = #core_types::extent::LevelIn::new(__level, <Self as #core_types::node::Node<#ctx_ident>>::layout(self).depth);
|
||||
__arg.at(__level_in)
|
||||
}
|
||||
}
|
||||
} else if node.output.shape.depth > 0 {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use core_types::context::{ContextModification, Ctx, DeriveCtx};
|
||||
use core_types::extent::{ExtentIn, LevelIn, ValueIn};
|
||||
use core_types::gpoll::{Extent, GPoll, Interrupt};
|
||||
use core_types::gpoll::Interrupt;
|
||||
|
||||
/// Filters out what should be unused components of the context based on the specified requirements.
|
||||
/// This node is inserted by the compiler to "zero out" unused context components.
|
||||
#[node_macro::node(category(""), extent(context_modification_extent))]
|
||||
#[node_macro::node(category(""))]
|
||||
fn context_modification<T>(
|
||||
ctx: impl Ctx + DeriveCtx,
|
||||
/// The data to pass through, evaluated with the stripped down context.
|
||||
@@ -15,7 +14,3 @@ fn context_modification<T>(
|
||||
let scope = ctx.scope().nullified(modification.features, Some(modification.sources()));
|
||||
value.eval(&ctx.nullified(modification.features, &scope))
|
||||
}
|
||||
|
||||
fn context_modification_extent(value: ExtentIn<'_>, _modification: ValueIn<'_, ContextModification>, level: LevelIn) -> GPoll<Extent> {
|
||||
value.at(level)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use core_types::Ctx;
|
||||
use core_types::list::List;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use raster_types::{CPU, Raster};
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use core_types::arena::ArenaCell;
|
||||
use core_types::context::{Ctx, CtxSnapshot, DeriveCtx, ExtractAll, InjectIndex};
|
||||
use core_types::extent::{ExtentIn, LevelIn};
|
||||
use core_types::frame_table::{FrameTable, Lookup};
|
||||
use core_types::gpoll::{Extent, Finality, GPoll};
|
||||
use core_types::gpoll::{Finality, GPoll};
|
||||
use core_types::graphene_hash::CacheHash;
|
||||
use core_types::memo::IORecord;
|
||||
use core_types::record::{LevelStatus, OwnedRecord, RecordCapture, RecordValue, copy_record_bytes, record_from_bytes};
|
||||
@@ -13,7 +12,7 @@ use std::sync::Mutex;
|
||||
/// Helps speed up repeated renders in a computationally-heavy part of the node graph.
|
||||
///
|
||||
/// Stores a deep copy of the last record that flowed through this node and replays it on subsequent renders if the context has not changed.
|
||||
#[node_macro::node(category("General"), path(graphene_core::memo), extent(memoize_extent))]
|
||||
#[node_macro::node(category("General"), path(graphene_core::memo))]
|
||||
fn memoize<'e>(
|
||||
ctx: impl Ctx + CacheHash + ExtractArena<'e>,
|
||||
#[data] cache: Arc<Mutex<Option<(u64, OwnedRecord, Finality)>>>,
|
||||
@@ -45,11 +44,7 @@ fn memoize<'e>(
|
||||
result
|
||||
}
|
||||
|
||||
fn memoize_extent(content: ExtentIn<'_>, level: LevelIn) -> GPoll<Extent> {
|
||||
content.at(level)
|
||||
}
|
||||
|
||||
#[node_macro::node(category(""), path(graphene_core::memo), extent(frame_memo_extent))]
|
||||
#[node_macro::node(category(""), path(graphene_core::memo))]
|
||||
fn frame_memo<'e>(
|
||||
ctx: impl Ctx + CacheHash + ExtractArena<'e>,
|
||||
#[data] cell: ArenaCell<FrameTable<Box<[u8]>, 32>>,
|
||||
@@ -92,14 +87,10 @@ fn frame_memo<'e>(
|
||||
}
|
||||
}
|
||||
|
||||
fn frame_memo_extent(content: ExtentIn<'_>, level: LevelIn) -> GPoll<Extent> {
|
||||
content.at(level)
|
||||
}
|
||||
|
||||
type MonitorValue = Arc<Mutex<Option<IORecord<CtxSnapshot, RecordCapture>>>>;
|
||||
|
||||
/// The Monitor node is used by the editor to access the data flowing through it.
|
||||
#[node_macro::node(category(""), path(graphene_core::memo), serialize(serialize_monitor), properties("monitor_properties"), extent(monitor_extent))]
|
||||
#[node_macro::node(category(""), path(graphene_core::memo), serialize(serialize_monitor), properties("monitor_properties"))]
|
||||
fn monitor<'e>(
|
||||
ctx: impl Ctx + DeriveCtx + ExtractAll + ExtractArena<'e> + InjectIndex + Copy,
|
||||
#[data] io: MonitorValue,
|
||||
@@ -126,10 +117,6 @@ fn monitor<'e>(
|
||||
result
|
||||
}
|
||||
|
||||
fn monitor_extent(content: ExtentIn<'_>, level: LevelIn) -> GPoll<Extent> {
|
||||
content.at(level)
|
||||
}
|
||||
|
||||
fn serialize_monitor(io: &MonitorValue) -> Option<Arc<dyn std::any::Any + Send + Sync>> {
|
||||
let io = io.lock().unwrap();
|
||||
io.as_ref().map(|io| Arc::new(io.clone()) as Arc<dyn std::any::Any + Send + Sync>)
|
||||
|
||||
@@ -4,15 +4,11 @@ use core_types::{Ctx, ops::Convert, ops::ConvertAsync, transform::Footprint};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// Passes-through the input value without changing it. This is useful for rerouting wires for organization purposes.
|
||||
#[node_macro::node(category("General"), skip_impl, extent(passthrough_extent))]
|
||||
#[node_macro::node(category("General"), skip_impl)]
|
||||
fn passthrough<T: Send>(_: impl Ctx, content: T) -> T {
|
||||
content
|
||||
}
|
||||
|
||||
fn passthrough_extent(content: core_types::extent::ExtentIn<'_>, level: core_types::extent::LevelIn) -> core_types::gpoll::GPoll<core_types::gpoll::Extent> {
|
||||
content.at(level)
|
||||
}
|
||||
|
||||
#[node_macro::node(category(""), skip_impl)]
|
||||
fn into<T: Send + Into<O>, O: Send>(_: impl Ctx, value: T, #[data] _out_ty: PhantomData<O>) -> O {
|
||||
value.into()
|
||||
|
||||
Reference in New Issue
Block a user