1use std::collections::{BTreeMap, HashMap};
2
3use std::iter;
4use std::rc::Rc;
5use_RefCell!();
6use crate::api::{math::Point2, CommonProperties, RenderContext, SceneAmbientLight, SceneLight};
7use pax_manifest::cartridge_generation::ComponentTransitionConfig;
8use pax_manifest::{
9 SettingsBlockElement, TemplateNodeSelectorInfo, TypeId, UniqueTemplateNodeIdentifier,
10};
11use pax_message::NativeInterrupt;
12use pax_runtime_api::pax_value::PaxAny;
13use pax_runtime_api::{borrow, use_RefCell, Variable};
14use piet::{Color, StrokeStyle};
15
16use crate::api::{Layer, Scroll, Window};
17
18use crate::{
19 create_new_common_properties, create_new_common_properties_from_columns,
20 property_columns_from_defined_properties, update_existing_common_properties,
21 update_existing_common_properties_from_columns, ErasedComponentDescriptor, ExpandedNode,
22 HandlerRegistry, ReceivedChildrenSource, RuntimeContext, RuntimePropertiesStackFrame,
23 TemplatePropertyPlan,
24};
25use pax_manifest::ValueDefinition;
26
27pub type InstanceNodePtr = Rc<dyn InstanceNode>;
30pub type InstanceNodePtrList = RefCell<Vec<InstanceNodePtr>>;
31pub type CommonPropertiesFactory = Box<
32 dyn Fn(
33 Rc<RuntimePropertiesStackFrame>,
34 Option<Rc<ExpandedNode>>,
35 ) -> Option<Rc<RefCell<CommonProperties>>>,
36>;
37pub type PropertiesFactory = Box<
38 dyn Fn(
39 Rc<RuntimePropertiesStackFrame>,
40 Option<Rc<ExpandedNode>>,
41 ) -> Option<Rc<RefCell<PaxAny>>>,
42>;
43pub type PropertiesScopeFactory = Box<dyn Fn(Rc<RefCell<PaxAny>>) -> HashMap<String, Variable>>;
44
45pub enum CommonPropertiesInit {
47 Default,
48 Inline {
49 defined_properties: BTreeMap<String, ValueDefinition>,
50 },
51 Template(Rc<TemplatePropertyPlan>),
52 Factory(CommonPropertiesFactory),
53}
54
55impl CommonPropertiesInit {
56 fn requires_pre_node_binding(&self) -> bool {
57 match self {
58 Self::Factory(_) => true,
59 Self::Inline { defined_properties } => defined_properties
60 .values()
61 .any(crate::value_uses_local_property_scope),
62 Self::Template(plan) => plan.requires_pre_node_binding,
63 Self::Default => false,
64 }
65 }
66
67 pub(crate) fn allocate(
70 &self,
71 stack: Rc<RuntimePropertiesStackFrame>,
72 ) -> Rc<RefCell<CommonProperties>> {
73 match self {
74 Self::Factory(factory) => {
75 factory(stack, None).expect("common properties factory must allocate properties")
76 }
77 _ => Rc::new(RefCell::new(CommonProperties::default())),
78 }
79 }
80
81 pub fn materialize(
82 &self,
83 stack_frame: Rc<RuntimePropertiesStackFrame>,
84 expanded_node: Option<Rc<ExpandedNode>>,
85 ) -> Option<Rc<RefCell<CommonProperties>>> {
86 match self {
87 CommonPropertiesInit::Default => expanded_node
88 .is_none()
89 .then(|| Rc::new(RefCell::new(CommonProperties::default()))),
90 CommonPropertiesInit::Inline { defined_properties } => {
91 if let Some(expanded_node) = expanded_node {
92 update_existing_common_properties(
93 &expanded_node,
94 defined_properties,
95 &stack_frame,
96 );
97 None
98 } else {
99 Some(create_new_common_properties(
100 defined_properties,
101 &stack_frame,
102 ))
103 }
104 }
105 CommonPropertiesInit::Template(plan) => {
106 let columns = plan.resolve(expanded_node.as_ref());
107 if let Some(node) = expanded_node {
108 update_existing_common_properties_from_columns(&node, &columns, &stack_frame);
109 None
110 } else {
111 Some(create_new_common_properties_from_columns(
112 &columns,
113 &stack_frame,
114 ))
115 }
116 }
117 CommonPropertiesInit::Factory(factory) => factory(stack_frame, expanded_node),
118 }
119 }
120}
121
122pub enum PropertiesInit {
124 DescriptorDefault(&'static ErasedComponentDescriptor),
125 DescriptorInline {
126 descriptor: &'static ErasedComponentDescriptor,
127 defined_properties: BTreeMap<String, ValueDefinition>,
128 },
129 Template {
130 descriptor: &'static ErasedComponentDescriptor,
131 plan: Rc<TemplatePropertyPlan>,
132 },
133 Factory(PropertiesFactory),
134}
135
136impl PropertiesInit {
137 pub fn adopt(self, properties: Rc<RefCell<PaxAny>>) -> Self {
141 Self::Factory(Box::new(move |stack, node| {
142 if node.is_none() {
143 Some(properties.clone())
144 } else {
145 self.materialize(stack, node)
146 }
147 }))
148 }
149
150 fn requires_pre_node_binding(&self) -> bool {
151 match self {
152 Self::Factory(_) => true,
153 Self::DescriptorInline {
154 defined_properties, ..
155 } => defined_properties
156 .values()
157 .any(crate::value_uses_local_property_scope),
158 Self::Template { plan, .. } => plan.requires_pre_node_binding,
159 Self::DescriptorDefault(_) => false,
160 }
161 }
162
163 pub(crate) fn allocate(&self, stack: Rc<RuntimePropertiesStackFrame>) -> Rc<RefCell<PaxAny>> {
165 match self {
166 Self::DescriptorDefault(descriptor)
167 | Self::DescriptorInline { descriptor, .. }
168 | Self::Template { descriptor, .. } => {
169 Rc::new(RefCell::new((descriptor.create_properties)()))
170 }
171 Self::Factory(factory) => {
172 factory(stack, None).expect("properties factory must allocate properties")
173 }
174 }
175 }
176
177 pub fn materialize(
178 &self,
179 stack_frame: Rc<RuntimePropertiesStackFrame>,
180 expanded_node: Option<Rc<ExpandedNode>>,
181 ) -> Option<Rc<RefCell<PaxAny>>> {
182 match self {
183 PropertiesInit::DescriptorDefault(descriptor) => expanded_node
184 .is_none()
185 .then(|| Rc::new(RefCell::new((descriptor.create_properties)()))),
186 PropertiesInit::DescriptorInline {
187 descriptor,
188 defined_properties,
189 } => {
190 if let Some(expanded_node) = expanded_node {
191 let outer_ref = expanded_node.properties.borrow();
192 let rc = Rc::clone(&outer_ref);
193 let mut inner_ref = (*rc).borrow_mut();
194 (descriptor.apply_defined_properties)(
195 descriptor.typed_descriptor,
196 &mut inner_ref,
197 &property_columns_from_defined_properties(defined_properties),
198 &stack_frame,
199 Some(&expanded_node),
200 );
201 None
202 } else {
203 let mut properties = (descriptor.create_properties)();
204 (descriptor.apply_defined_properties)(
205 descriptor.typed_descriptor,
206 &mut properties,
207 &property_columns_from_defined_properties(defined_properties),
208 &stack_frame,
209 None,
210 );
211 Some(Rc::new(RefCell::new(properties)))
212 }
213 }
214 PropertiesInit::Template { descriptor, plan } => {
215 let columns = plan.resolve(expanded_node.as_ref());
216 if let Some(node) = expanded_node {
217 let properties = Rc::clone(&node.properties.borrow());
218 (descriptor.apply_defined_properties)(
219 descriptor.typed_descriptor,
220 &mut properties.borrow_mut(),
221 &columns,
222 &stack_frame,
223 Some(&node),
224 );
225 None
226 } else {
227 let mut properties = (descriptor.create_properties)();
228 (descriptor.apply_defined_properties)(
229 descriptor.typed_descriptor,
230 &mut properties,
231 &columns,
232 &stack_frame,
233 None,
234 );
235 Some(Rc::new(RefCell::new(properties)))
236 }
237 }
238 PropertiesInit::Factory(factory) => factory(stack_frame, expanded_node),
239 }
240 }
241}
242
243pub enum PropertiesScopeInit {
245 None,
246 Descriptor(&'static ErasedComponentDescriptor),
247 Factory(PropertiesScopeFactory),
248}
249
250impl PropertiesScopeInit {
251 pub fn build(&self, properties: Rc<RefCell<PaxAny>>) -> HashMap<String, Variable> {
252 match self {
253 PropertiesScopeInit::None => HashMap::new(),
254 PropertiesScopeInit::Descriptor(descriptor) => {
255 let props_ref = borrow!(properties.as_ref());
256 (descriptor.build_property_scope)(descriptor.typed_descriptor, &props_ref)
257 }
258 PropertiesScopeInit::Factory(factory) => factory(properties),
259 }
260 }
261}
262
263pub struct InstantiationArgs {
265 pub prototypical_common_properties: CommonPropertiesInit,
266 pub prototypical_properties: PropertiesInit,
267 pub handler_registry: Option<Rc<RefCell<HandlerRegistry>>>,
268 pub children: Option<InstanceNodePtrList>,
269 pub component_template: Option<InstanceNodePtrList>,
270 pub component_settings: Option<Vec<SettingsBlockElement>>,
271
272 pub template_node_identifier: Option<UniqueTemplateNodeIdentifier>,
273 pub template_node_type_id: Option<TypeId>,
274 pub template_node_selector_info: Option<TemplateNodeSelectorInfo>,
275 pub transition_config: ComponentTransitionConfig,
276 pub properties_scope: PropertiesScopeInit,
278}
279
280pub struct ReusableInstanceNodeArgs {
282 pub handler_registry: Option<Rc<RefCell<HandlerRegistry>>>,
283 pub children: InstanceNodePtrList,
284 pub template_node_identifier: Option<UniqueTemplateNodeIdentifier>,
285 pub template_node_type_id: Option<TypeId>,
286 pub template_node_selector_info: Option<TemplateNodeSelectorInfo>,
287}
288
289impl ReusableInstanceNodeArgs {
290 pub fn new(base: &BaseInstance) -> Self {
292 ReusableInstanceNodeArgs {
293 handler_registry: base.handler_registry.clone(),
294 children: base.instance_children.clone(),
295 template_node_identifier: base.template_node_identifier.clone(),
296 template_node_type_id: base.template_node_type_id.clone(),
297 template_node_selector_info: base.template_node_selector_info.clone(),
298 }
299 }
300}
301
302#[derive(Clone)]
303pub enum NodeType {
305 Component,
306 Primitive,
307}
308
309impl std::fmt::Debug for dyn InstanceNode {
310 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
311 self.resolve_debug(f, None)
312 }
313}
314
315pub trait InstanceNode {
330 #[cfg(feature = "shaders")]
338 fn shader_effect(&self, _node: &ExpandedNode) -> Option<pax_runtime_api::ShaderEffect> {
339 None
340 }
341 fn supports_alpha_source_render(&self) -> bool {
344 false
345 }
346 fn base(&self) -> &BaseInstance;
348
349 fn instantiate(args: InstantiationArgs) -> Rc<Self>
350 where
351 Self: Sized;
352
353 fn resolve_debug(
354 &self,
355 f: &mut std::fmt::Formatter,
356 expanded_node: Option<&ExpandedNode>,
357 ) -> std::fmt::Result;
358
359 fn requires_non_reactive_update(&self, _expanded_node: &ExpandedNode) -> bool {
362 false
363 }
364
365 fn has_scene_lighting(&self) -> bool {
371 false
372 }
373
374 fn resolve_scene_light(
376 &self,
377 _expanded_node: &ExpandedNode,
378 _context: &RuntimeContext,
379 ) -> Option<SceneLight> {
380 None
381 }
382
383 fn resolve_scene_ambient_light(
385 &self,
386 _expanded_node: &ExpandedNode,
387 _context: &RuntimeContext,
388 ) -> Option<SceneAmbientLight> {
389 None
390 }
391
392 fn establishes_light_frame(&self) -> bool {
394 false
395 }
396
397 fn update(self: Rc<Self>, _expanded_node: &Rc<ExpandedNode>, _context: &Rc<RuntimeContext>) {}
399
400 #[allow(unused_variables)]
406 fn handle_pre_render(
407 &self,
408 expanded_node: &ExpandedNode,
409 context: &Rc<RuntimeContext>,
410 rcs: &mut dyn RenderContext,
411 ) {
412 }
414
415 fn prepare_canvas_geometry(
424 &self,
425 _node: &ExpandedNode,
426 ) -> crate::scene_geometry::CanvasGeometry {
427 Default::default()
428 }
429
430 #[allow(unused_variables)]
435 fn render(
436 &self,
437 expanded_node: &ExpandedNode,
438 context: &Rc<RuntimeContext>,
439 rcs: &mut dyn RenderContext,
440 ) {
441 }
442
443 #[allow(unused_variables)]
449 fn handle_post_render(
450 &self,
451 expanded_node: &ExpandedNode,
452 context: &Rc<RuntimeContext>,
453 rcs: &mut dyn RenderContext,
454 ) {
455 }
457
458 #[allow(unused_variables)]
463 fn handle_mount(
464 self: Rc<Self>,
465 expanded_node: &Rc<ExpandedNode>,
466 context: &Rc<RuntimeContext>,
467 ) {
468 let env = Rc::clone(&expanded_node.stack);
469 let children = borrow!(self.base().get_instance_children());
470 let children_with_envs = children.iter().cloned().zip(iter::repeat(env));
471
472 let new_children = expanded_node.generate_children(
473 children_with_envs,
474 context,
475 &expanded_node.parent_frame,
476 true,
477 );
478 expanded_node.children.set(new_children);
479 #[cfg(feature = "shaders")]
480 if self.shader_effect(expanded_node).is_some() {
481 crate::bind_shader_effect(expanded_node, context);
482 }
483 }
484
485 #[allow(unused_variables)]
488 fn handle_unmount(&self, expanded_node: &Rc<ExpandedNode>, context: &Rc<RuntimeContext>) {
489 }
493
494 #[allow(unused_variables)]
496 fn handle_scroll(&self, args_scroll: Scroll) {
497 }
499
500 fn get_template(&self) -> Option<&InstanceNodePtrList> {
501 None
502 }
503
504 fn clips_content(&self, _expanded_node: &ExpandedNode) -> bool {
506 false
507 }
508
509 fn ray_cast_test(&self, expanded_node: &ExpandedNode, ray: Point2<Window>) -> bool {
511 let t_and_b = expanded_node.transform_and_bounds.get();
512 let inverted_transform = t_and_b.transform.inverse();
513 let transformed_ray = inverted_transform * ray;
514 let (width, height) = t_and_b.bounds;
515 transformed_ray.x > 0.0
516 && transformed_ray.y > 0.0
517 && transformed_ray.x < width
518 && transformed_ray.y < height
519 }
520
521 fn scrolls_content(&self, _expanded_node: &ExpandedNode) -> bool {
523 false
524 }
525
526 fn property_requires_occlusion_recompute(&self, _property_name: &str) -> bool {
535 true
536 }
537
538 fn materializes_native_surface(&self, _expanded_node: &ExpandedNode) -> bool {
540 false
541 }
542
543 fn materializes_native_surface_before_children(&self, _expanded_node: &ExpandedNode) -> bool {
550 false
551 }
552
553 fn resolve_scroll_offset(&self, _expanded_node: &ExpandedNode) -> Option<(f64, f64)> {
555 None
556 }
557
558 fn received_children_source(&self) -> ReceivedChildrenSource {
571 if self.base().flags().is_component {
572 ReceivedChildrenSource::Projected
573 } else {
574 ReceivedChildrenSource::Owned
575 }
576 }
577
578 fn handle_native_interrupt(
579 &self,
580 _expanded_node: &Rc<ExpandedNode>,
581 _interrupt: &NativeInterrupt,
582 ) {
583 }
585
586 fn handle_control_flow_node_expansion(
587 self: Rc<Self>,
588 _expanded_node: &Rc<ExpandedNode>,
589 _context: &Rc<RuntimeContext>,
590 ) {
591 }
592
593 fn handle_setup_projected_children(
594 self: Rc<Self>,
595 _expanded_node: &Rc<ExpandedNode>,
596 _context: &Rc<RuntimeContext>,
597 ) {
598 }
599
600 fn resolve_coverage_path(&self, _expanded_node: &ExpandedNode) -> Option<kurbo::BezPath> {
601 None
602 }
603
604 fn resolve_alpha_mask_paints(
609 &self,
610 _expanded_node: &ExpandedNode,
611 ) -> Vec<pax_runtime_api::AlphaMaskPaint> {
612 Vec::new()
613 }
614
615 fn resolve_occlusion_path(&self, expanded_node: &ExpandedNode) -> Option<kurbo::BezPath> {
621 self.resolve_coverage_path(expanded_node)
622 }
623
624 fn resolve_coverage_opacity(&self, expanded_node: &ExpandedNode) -> f64 {
625 expanded_node.computed_opacity.get()
626 }
627
628 fn resolve_effect_clip_path(&self, _expanded_node: &ExpandedNode) -> Option<kurbo::BezPath> {
629 None
630 }
631}
632
633pub struct BaseInstance {
635 pub handler_registry: Option<Rc<RefCell<HandlerRegistry>>>,
636 pub instance_prototypical_properties: PropertiesInit,
637 pub instance_prototypical_common_properties: CommonPropertiesInit,
638 pub component_settings: Option<Vec<SettingsBlockElement>>,
639 pub template_node_identifier: Option<UniqueTemplateNodeIdentifier>,
640 pub template_node_type_id: Option<TypeId>,
641 pub template_node_selector_info: Option<TemplateNodeSelectorInfo>,
642 pub transition_config: ComponentTransitionConfig,
643 pub properties_scope: PropertiesScopeInit,
644 instance_children: InstanceNodePtrList,
645 flags: InstanceFlags,
646}
647
648#[derive(Clone)]
649pub struct InstanceFlags {
651 pub invisible_to_slot: bool,
656 pub invisible_to_raycasting: bool,
660 pub layer: Layer,
665
666 pub is_component: bool,
668
669 pub is_slot: bool,
671}
672
673impl BaseInstance {
674 pub(crate) fn requires_pre_node_binding(&self) -> bool {
675 self.instance_prototypical_common_properties
676 .requires_pre_node_binding()
677 || self
678 .instance_prototypical_properties
679 .requires_pre_node_binding()
680 || matches!(self.properties_scope, PropertiesScopeInit::Factory(_))
681 }
682
683 pub(crate) fn bind_properties(&self, node: &Rc<ExpandedNode>) {
688 if let (
689 CommonPropertiesInit::Template(common_plan),
690 PropertiesInit::Template { descriptor, plan },
691 ) = (
692 &self.instance_prototypical_common_properties,
693 &self.instance_prototypical_properties,
694 ) {
695 if Rc::ptr_eq(common_plan, plan) {
696 let columns = plan.resolve(Some(node));
697 update_existing_common_properties_from_columns(node, &columns, &node.stack);
698 let properties = Rc::clone(&node.properties.borrow());
699 (descriptor.apply_defined_properties)(
700 descriptor.typed_descriptor,
701 &mut properties.borrow_mut(),
702 &columns,
703 &node.stack,
704 Some(node),
705 );
706 return;
707 }
708 }
709 self.instance_prototypical_common_properties
710 .materialize(Rc::clone(&node.stack), Some(Rc::clone(node)));
711 self.instance_prototypical_properties
712 .materialize(Rc::clone(&node.stack), Some(Rc::clone(node)));
713 }
714
715 pub fn new(args: InstantiationArgs, flags: InstanceFlags) -> Self {
717 BaseInstance {
718 handler_registry: args.handler_registry,
719 instance_prototypical_common_properties: args.prototypical_common_properties,
720 instance_prototypical_properties: args.prototypical_properties,
721 component_settings: args.component_settings,
722 instance_children: args.children.unwrap_or_default(),
723 flags,
724 template_node_identifier: args.template_node_identifier,
725 template_node_type_id: args.template_node_type_id,
726 template_node_selector_info: args.template_node_selector_info,
727 transition_config: args.transition_config,
728 properties_scope: args.properties_scope,
729 }
730 }
731
732 pub fn get_handler_registry(&self) -> Option<Rc<RefCell<HandlerRegistry>>> {
737 match &self.handler_registry {
738 Some(registry) => Some(Rc::clone(registry)),
739 _ => None,
740 }
741 }
742
743 pub fn get_instance_children(&self) -> &InstanceNodePtrList {
749 &self.instance_children
750 }
751
752 pub fn flags(&self) -> &InstanceFlags {
754 &self.flags
755 }
756
757 pub fn transition_config(&self) -> &ComponentTransitionConfig {
758 &self.transition_config
759 }
760}
761
762pub struct StrokeInstance {
764 pub color: Color,
765 pub width: f64,
766 pub style: StrokeStyle,
767}