1use std::{
4 any::{Any, TypeId},
5 cell::RefCell,
6 collections::HashMap,
7 hash::{DefaultHasher, Hash, Hasher},
8};
9
10use crate::{
11 ComputeResourceManager, ComputedData, Constraint, MeasurementError, ParentConstraint, Px,
12 RenderSlot,
13 component_tree::{
14 ComponentNodeMetaData, ComponentNodeMetaDatas, ComponentNodeTree, LayoutContext,
15 measure_node,
16 },
17 modifier::{Modifier, OrderedModifierAction, ParentDataMap},
18 prop::Prop,
19 px::PxPosition,
20 render_graph::RenderFragment,
21 runtime::TesseraRuntime,
22 tessera,
23};
24
25#[derive(Clone, Copy)]
26pub(crate) struct ChildMeasure {
27 pub constraint: Constraint,
28 pub size: ComputedData,
29 pub consistent: bool,
30}
31
32pub struct LayoutInput<'a> {
34 tree: &'a ComponentNodeTree,
35 parent_constraint: ParentConstraint<'a>,
36 children_ids: &'a [crate::NodeId],
37 metadatas: *mut ComponentNodeMetaDatas,
38 layout_ctx: Option<&'a LayoutContext<'a>>,
39 measured_children: RefCell<HashMap<crate::NodeId, ChildMeasure>>,
40}
41
42#[derive(Clone, Copy)]
44pub struct LayoutChild<'a> {
45 node_id: crate::NodeId,
46 instance_key: u64,
47 tree: &'a ComponentNodeTree,
48 metadatas: *mut ComponentNodeMetaDatas,
49 layout_ctx: Option<&'a LayoutContext<'a>>,
50 measured_children: &'a RefCell<HashMap<crate::NodeId, ChildMeasure>>,
51}
52
53impl PartialEq for LayoutChild<'_> {
54 fn eq(&self, other: &Self) -> bool {
55 self.node_id == other.node_id
56 }
57}
58
59impl Eq for LayoutChild<'_> {}
60
61impl Hash for LayoutChild<'_> {
62 fn hash<H: Hasher>(&self, state: &mut H) {
63 self.node_id.hash(state);
64 }
65}
66
67impl<'a> LayoutChild<'a> {
68 pub fn measure(&self, constraint: &Constraint) -> Result<MeasuredChild, MeasurementError> {
70 let metadatas = unsafe { &mut *self.metadatas };
74 let size = measure_node(
75 self.node_id,
76 constraint,
77 self.tree,
78 metadatas,
79 self.layout_ctx,
80 )?;
81 let mut measured_children = self.measured_children.borrow_mut();
82 if let Some(entry) = measured_children.get_mut(&self.node_id) {
83 let consistent =
84 entry.consistent && entry.constraint == *constraint && entry.size == size;
85 entry.constraint = *constraint;
86 entry.size = size;
87 entry.consistent = consistent;
88 } else {
89 measured_children.insert(
90 self.node_id,
91 ChildMeasure {
92 constraint: *constraint,
93 size,
94 consistent: true,
95 },
96 );
97 }
98 Ok(MeasuredChild {
99 instance_key: self.instance_key,
100 width: size.width,
101 height: size.height,
102 })
103 }
104
105 pub fn measure_untracked(
107 &self,
108 constraint: &Constraint,
109 ) -> Result<MeasuredChild, MeasurementError> {
110 let metadatas = unsafe { &mut *self.metadatas };
112 let size = measure_node(
113 self.node_id,
114 constraint,
115 self.tree,
116 metadatas,
117 self.layout_ctx,
118 )?;
119 Ok(MeasuredChild {
120 instance_key: self.instance_key,
121 width: size.width,
122 height: size.height,
123 })
124 }
125
126 pub fn parent_data<T>(&self) -> Option<T>
128 where
129 T: Clone + Send + Sync + 'static,
130 {
131 let node = self.tree.get(self.node_id)?;
132 let mut data: ParentDataMap = HashMap::default();
133 for action in node.get().modifier.ordered_actions() {
134 if let OrderedModifierAction::ParentData(node) = action {
135 node.apply_parent_data(&mut data);
136 }
137 }
138 let value = data.get(&TypeId::of::<T>())?;
139 value.downcast_ref::<T>().cloned()
140 }
141
142 pub(crate) const fn instance_key(&self) -> u64 {
143 self.instance_key
144 }
145}
146
147#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
149pub struct MeasuredChild {
150 instance_key: u64,
151 pub width: Px,
153 pub height: Px,
155}
156
157impl MeasuredChild {
158 pub const fn size(&self) -> ComputedData {
160 ComputedData {
161 width: self.width,
162 height: self.height,
163 }
164 }
165
166 pub(crate) const fn instance_key(&self) -> u64 {
167 self.instance_key
168 }
169}
170
171#[derive(Clone, Copy)]
173pub struct PlacementChild<'a> {
174 node_id: crate::NodeId,
175 instance_key: u64,
176 tree: &'a ComponentNodeTree,
177 size: ComputedData,
178}
179
180impl<'a> PlacementChild<'a> {
181 pub const fn size(&self) -> ComputedData {
183 self.size
184 }
185
186 pub fn parent_data<T>(&self) -> Option<T>
188 where
189 T: Clone + Send + Sync + 'static,
190 {
191 let node = self.tree.get(self.node_id)?;
192 let mut data: ParentDataMap = HashMap::default();
193 for action in node.get().modifier.ordered_actions() {
194 if let OrderedModifierAction::ParentData(node) = action {
195 node.apply_parent_data(&mut data);
196 }
197 }
198 let value = data.get(&TypeId::of::<T>())?;
199 value.downcast_ref::<T>().cloned()
200 }
201
202 pub(crate) const fn instance_key(&self) -> u64 {
203 self.instance_key
204 }
205}
206
207pub struct MeasureScope<'a> {
209 tree: &'a ComponentNodeTree,
210 metadatas: *mut ComponentNodeMetaDatas,
211 layout_ctx: Option<&'a LayoutContext<'a>>,
212 measured_children: &'a RefCell<HashMap<crate::NodeId, ChildMeasure>>,
213 parent_constraint: ParentConstraint<'a>,
214 children_ids: &'a [crate::NodeId],
215}
216
217impl<'a> MeasureScope<'a> {
218 pub(crate) fn new(
219 tree: &'a ComponentNodeTree,
220 metadatas: *mut ComponentNodeMetaDatas,
221 layout_ctx: Option<&'a LayoutContext<'a>>,
222 measured_children: &'a RefCell<HashMap<crate::NodeId, ChildMeasure>>,
223 parent_constraint: ParentConstraint<'a>,
224 children_ids: &'a [crate::NodeId],
225 ) -> Self {
226 Self {
227 tree,
228 metadatas,
229 layout_ctx,
230 measured_children,
231 parent_constraint,
232 children_ids,
233 }
234 }
235
236 pub const fn parent_constraint(&self) -> ParentConstraint<'a> {
238 self.parent_constraint
239 }
240
241 pub fn children(&self) -> Vec<LayoutChild<'_>> {
243 self.children_ids
244 .iter()
245 .map(|&node_id| {
246 let instance_key = self
247 .tree
248 .get(node_id)
249 .expect("Direct child layout node must exist")
250 .get()
251 .instance_key;
252 LayoutChild {
253 node_id,
254 instance_key,
255 tree: self.tree,
256 metadatas: self.metadatas,
257 layout_ctx: self.layout_ctx,
258 measured_children: self.measured_children,
259 }
260 })
261 .collect()
262 }
263}
264
265pub struct PlacementScope<'a> {
267 tree: &'a ComponentNodeTree,
268 parent_constraint: ParentConstraint<'a>,
269 children_ids: &'a [crate::NodeId],
270 child_sizes: &'a HashMap<crate::NodeId, ComputedData>,
271 size: ComputedData,
272}
273
274impl<'a> PlacementScope<'a> {
275 pub(crate) fn new(
276 tree: &'a ComponentNodeTree,
277 parent_constraint: ParentConstraint<'a>,
278 children_ids: &'a [crate::NodeId],
279 child_sizes: &'a HashMap<crate::NodeId, ComputedData>,
280 size: ComputedData,
281 ) -> Self {
282 Self {
283 tree,
284 parent_constraint,
285 children_ids,
286 child_sizes,
287 size,
288 }
289 }
290
291 pub const fn parent_constraint(&self) -> ParentConstraint<'a> {
293 self.parent_constraint
294 }
295
296 pub fn children(&self) -> Vec<PlacementChild<'_>> {
298 self.children_ids
299 .iter()
300 .map(|&node_id| {
301 let node = self
302 .tree
303 .get(node_id)
304 .expect("Direct child layout node must exist");
305 PlacementChild {
306 node_id,
307 instance_key: node.get().instance_key,
308 tree: self.tree,
309 size: self
310 .child_sizes
311 .get(&node_id)
312 .copied()
313 .expect("Placement child size must exist for a direct child layout node"),
314 }
315 })
316 .collect()
317 }
318
319 pub const fn size(&self) -> ComputedData {
321 self.size
322 }
323}
324
325impl<'a> LayoutInput<'a> {
326 pub(crate) fn new(
327 tree: &'a ComponentNodeTree,
328 parent_constraint: ParentConstraint<'a>,
329 children_ids: &'a [crate::NodeId],
330 metadatas: *mut ComponentNodeMetaDatas,
331 layout_ctx: Option<&'a LayoutContext<'a>>,
332 ) -> Self {
333 Self {
334 tree,
335 parent_constraint,
336 children_ids,
337 metadatas,
338 layout_ctx,
339 measured_children: RefCell::new(HashMap::new()),
340 }
341 }
342
343 pub const fn parent_constraint(&self) -> ParentConstraint<'a> {
345 self.parent_constraint
346 }
347
348 pub(crate) fn take_measured_children(&self) -> HashMap<crate::NodeId, ChildMeasure> {
349 std::mem::take(&mut *self.measured_children.borrow_mut())
350 }
351
352 pub(crate) fn extend_measured_children(&self, children: HashMap<crate::NodeId, ChildMeasure>) {
353 let mut measured_children = self.measured_children.borrow_mut();
354 for (child_id, measurement) in children {
355 if let Some(entry) = measured_children.get_mut(&child_id) {
356 let consistent = entry.consistent
357 && entry.constraint == measurement.constraint
358 && entry.size == measurement.size
359 && measurement.consistent;
360 entry.constraint = measurement.constraint;
361 entry.size = measurement.size;
362 entry.consistent = consistent;
363 } else {
364 measured_children.insert(child_id, measurement);
365 }
366 }
367 }
368
369 pub(crate) fn measure_scope(&self) -> MeasureScope<'_> {
370 MeasureScope::new(
371 self.tree,
372 self.metadatas,
373 self.layout_ctx,
374 &self.measured_children,
375 self.parent_constraint,
376 self.children_ids,
377 )
378 }
379
380 pub fn children(&self) -> Vec<LayoutChild<'_>> {
382 self.children_ids
383 .iter()
384 .map(|&node_id| {
385 let instance_key = self
386 .tree
387 .get(node_id)
388 .expect("Direct child layout node must exist")
389 .get()
390 .instance_key;
391 LayoutChild {
392 node_id,
393 instance_key,
394 tree: self.tree,
395 metadatas: self.metadatas,
396 layout_ctx: self.layout_ctx,
397 measured_children: &self.measured_children,
398 }
399 })
400 .collect()
401 }
402}
403
404#[derive(Clone)]
406pub struct LayoutResult {
407 pub size: ComputedData,
409 pub placements: Vec<(u64, PxPosition)>,
411}
412
413impl LayoutResult {
414 pub const fn new(size: ComputedData) -> Self {
416 Self {
417 size,
418 placements: Vec::new(),
419 }
420 }
421
422 pub fn place_child<T>(&mut self, child: T, position: PxPosition)
424 where
425 T: LayoutPlacementTarget,
426 {
427 self.placements.push((child.instance_key(), position));
428 }
429
430 pub const fn with_size(mut self, size: ComputedData) -> Self {
432 self.size = size;
433 self
434 }
435
436 pub fn into_placements(self) -> Vec<(u64, PxPosition)> {
438 self.placements
439 }
440}
441
442impl Default for LayoutResult {
443 fn default() -> Self {
444 Self::new(ComputedData::ZERO)
445 }
446}
447
448pub trait LayoutPlacementTarget: Copy {
450 #[doc(hidden)]
451 fn instance_key(&self) -> u64;
452}
453
454impl LayoutPlacementTarget for LayoutChild<'_> {
455 fn instance_key(&self) -> u64 {
456 self.instance_key()
457 }
458}
459
460impl LayoutPlacementTarget for MeasuredChild {
461 fn instance_key(&self) -> u64 {
462 self.instance_key()
463 }
464}
465
466impl LayoutPlacementTarget for PlacementChild<'_> {
467 fn instance_key(&self) -> u64 {
468 self.instance_key()
469 }
470}
471
472pub struct RenderInput<'a> {
474 current_node_id: crate::NodeId,
475 metadatas: &'a mut ComponentNodeMetaDatas,
476 pub compute_resource_manager: &'a mut ComputeResourceManager,
478 pub gpu: &'a wgpu::Device,
480}
481
482impl<'a> RenderInput<'a> {
483 pub(crate) fn new(
484 current_node_id: crate::NodeId,
485 metadatas: &'a mut ComponentNodeMetaDatas,
486 compute_resource_manager: &'a mut ComputeResourceManager,
487 gpu: &'a wgpu::Device,
488 ) -> Self {
489 Self {
490 current_node_id,
491 metadatas,
492 compute_resource_manager,
493 gpu,
494 }
495 }
496
497 pub fn metadata_mut(&mut self) -> RenderMetadataMut<'_> {
499 let metadata = self
500 .metadatas
501 .get_mut(&self.current_node_id)
502 .expect("Metadata for current node must exist during record");
503 RenderMetadataMut { metadata }
504 }
505}
506
507pub struct RenderMetadataMut<'a> {
509 metadata: &'a mut ComponentNodeMetaData,
510}
511
512impl RenderMetadataMut<'_> {
513 pub fn computed_data(&self) -> Option<ComputedData> {
515 self.metadata.computed_data
516 }
517
518 pub fn fragment_mut(&mut self) -> &mut RenderFragment {
520 self.metadata.fragment_mut()
521 }
522
523 pub fn set_clips_children(&mut self, clips_children: bool) {
525 self.metadata.clips_children = clips_children;
526 }
527
528 pub fn multiply_opacity(&mut self, opacity: f32) {
530 self.metadata.opacity *= opacity;
531 }
532}
533
534pub trait LayoutPolicy: Send + Sync + Clone + PartialEq + 'static {
536 fn measure(&self, scope: &MeasureScope<'_>) -> Result<LayoutResult, MeasurementError>;
538
539 fn measure_eq(&self, other: &Self) -> bool {
541 self == other
542 }
543
544 fn placement_eq(&self, other: &Self) -> bool {
546 self == other
547 }
548
549 fn place_children(&self, _scope: &PlacementScope<'_>) -> Option<Vec<(u64, PxPosition)>> {
554 None
555 }
556}
557
558pub trait RenderPolicy: Send + Sync + Clone + PartialEq + 'static {
560 fn record(&self, _input: &mut RenderInput<'_>) {}
562}
563
564#[doc(hidden)]
566pub trait LayoutPolicyDyn: Send + Sync {
567 fn as_any(&self) -> &dyn Any;
569 fn measure_dyn(&self, scope: &MeasureScope<'_>) -> Result<LayoutResult, MeasurementError>;
571 fn place_children_dyn(&self, scope: &PlacementScope<'_>) -> Option<Vec<(u64, PxPosition)>>;
573 fn dyn_eq(&self, other: &dyn LayoutPolicyDyn) -> bool;
575 fn dyn_measure_eq(&self, other: &dyn LayoutPolicyDyn) -> bool;
577 fn dyn_placement_eq(&self, other: &dyn LayoutPolicyDyn) -> bool;
579 fn clone_box(&self) -> Box<dyn LayoutPolicyDyn>;
581}
582
583impl<T> LayoutPolicyDyn for T
584where
585 T: LayoutPolicy,
586{
587 fn as_any(&self) -> &dyn Any {
588 self
589 }
590
591 fn measure_dyn(&self, scope: &MeasureScope<'_>) -> Result<LayoutResult, MeasurementError> {
592 LayoutPolicy::measure(self, scope)
593 }
594
595 fn place_children_dyn(&self, scope: &PlacementScope<'_>) -> Option<Vec<(u64, PxPosition)>> {
596 LayoutPolicy::place_children(self, scope)
597 }
598
599 fn dyn_eq(&self, other: &dyn LayoutPolicyDyn) -> bool {
600 other
601 .as_any()
602 .downcast_ref::<T>()
603 .is_some_and(|other| self == other)
604 }
605
606 fn dyn_measure_eq(&self, other: &dyn LayoutPolicyDyn) -> bool {
607 other
608 .as_any()
609 .downcast_ref::<T>()
610 .is_some_and(|other| LayoutPolicy::measure_eq(self, other))
611 }
612
613 fn dyn_placement_eq(&self, other: &dyn LayoutPolicyDyn) -> bool {
614 other
615 .as_any()
616 .downcast_ref::<T>()
617 .is_some_and(|other| LayoutPolicy::placement_eq(self, other))
618 }
619
620 fn clone_box(&self) -> Box<dyn LayoutPolicyDyn> {
621 Box::new(self.clone())
622 }
623}
624
625#[doc(hidden)]
627pub trait RenderPolicyDyn: Send + Sync {
628 fn as_any(&self) -> &dyn Any;
630 fn record_dyn(&self, input: &mut RenderInput<'_>);
632 fn dyn_eq(&self, other: &dyn RenderPolicyDyn) -> bool;
634 fn clone_box(&self) -> Box<dyn RenderPolicyDyn>;
636}
637
638impl<T> RenderPolicyDyn for T
639where
640 T: RenderPolicy,
641{
642 fn as_any(&self) -> &dyn Any {
643 self
644 }
645
646 fn record_dyn(&self, input: &mut RenderInput<'_>) {
647 RenderPolicy::record(self, input);
648 }
649
650 fn dyn_eq(&self, other: &dyn RenderPolicyDyn) -> bool {
651 other
652 .as_any()
653 .downcast_ref::<T>()
654 .is_some_and(|other| self == other)
655 }
656
657 fn clone_box(&self) -> Box<dyn RenderPolicyDyn> {
658 Box::new(self.clone())
659 }
660}
661
662impl Clone for Box<dyn LayoutPolicyDyn> {
663 fn clone(&self) -> Self {
664 self.clone_box()
665 }
666}
667
668impl Clone for Box<dyn RenderPolicyDyn> {
669 fn clone(&self) -> Self {
670 self.clone_box()
671 }
672}
673
674#[derive(Clone)]
680pub struct LayoutPolicyHandle {
681 policy: Box<dyn LayoutPolicyDyn>,
682}
683
684impl LayoutPolicyHandle {
685 pub(crate) fn into_box(self) -> Box<dyn LayoutPolicyDyn> {
686 self.policy
687 }
688}
689
690impl Default for LayoutPolicyHandle {
691 fn default() -> Self {
692 Self {
693 policy: Box::new(DefaultLayoutPolicy),
694 }
695 }
696}
697
698impl PartialEq for LayoutPolicyHandle {
699 fn eq(&self, other: &Self) -> bool {
700 self.policy.dyn_eq(other.policy.as_ref())
701 }
702}
703
704impl Prop for LayoutPolicyHandle {
705 fn prop_eq(&self, other: &Self) -> bool {
706 self == other
707 }
708}
709
710impl<S> From<S> for LayoutPolicyHandle
711where
712 S: LayoutPolicy,
713{
714 fn from(policy: S) -> Self {
715 Self {
716 policy: Box::new(policy),
717 }
718 }
719}
720
721#[derive(Clone)]
727pub struct RenderPolicyHandle {
728 policy: Box<dyn RenderPolicyDyn>,
729}
730
731impl RenderPolicyHandle {
732 pub(crate) fn into_box(self) -> Box<dyn RenderPolicyDyn> {
733 self.policy
734 }
735}
736
737impl Default for RenderPolicyHandle {
738 fn default() -> Self {
739 Self {
740 policy: Box::new(NoopRenderPolicy),
741 }
742 }
743}
744
745impl PartialEq for RenderPolicyHandle {
746 fn eq(&self, other: &Self) -> bool {
747 self.policy.dyn_eq(other.policy.as_ref())
748 }
749}
750
751impl Prop for RenderPolicyHandle {
752 fn prop_eq(&self, other: &Self) -> bool {
753 self == other
754 }
755}
756
757impl<S> From<S> for RenderPolicyHandle
758where
759 S: RenderPolicy,
760{
761 fn from(policy: S) -> Self {
762 Self {
763 policy: Box::new(policy),
764 }
765 }
766}
767
768#[tessera(crate)]
806pub fn layout(
807 #[prop(into)] layout_policy: Option<LayoutPolicyHandle>,
808 #[prop(into)] render_policy: Option<RenderPolicyHandle>,
809 modifier: Option<Modifier>,
810 child: Option<RenderSlot>,
811) {
812 let layout_policy = layout_policy.unwrap_or(LayoutPolicyHandle::from(DefaultLayoutPolicy));
813 let render_policy = render_policy.unwrap_or(RenderPolicyHandle::from(NoopRenderPolicy));
814 let modifier = modifier.unwrap_or_default();
815 let layout_node_component_type_id = layout_node_component_type_id();
816 let layout_node_id =
817 crate::__private::register_layout_node("layout", layout_node_component_type_id);
818 let _layout_node_ctx_guard = crate::__private::push_current_node(
819 layout_node_id,
820 layout_node_component_type_id,
821 "layout",
822 );
823 let layout_instance_key = crate::__private::current_instance_key();
824 let layout_instance_logic_id = crate::__private::current_instance_logic_id();
825 let _layout_scope_guard = {
826 struct LayoutNodeScopeGuard;
827
828 impl Drop for LayoutNodeScopeGuard {
829 fn drop(&mut self) {
830 crate::__private::finish_component_node();
831 }
832 }
833
834 LayoutNodeScopeGuard
835 };
836
837 crate::__private::set_current_node_identity(layout_instance_key, layout_instance_logic_id);
838 modifier.attach();
839 TesseraRuntime::with_mut(|runtime| {
840 runtime.set_current_layout_policy_boxed(layout_policy.into_box());
841 runtime.set_current_render_policy_boxed(render_policy.into_box());
842 });
843 if let Some(child) = child {
844 child.render();
845 }
846}
847
848fn layout_node_component_type_id() -> u64 {
849 let mut hasher = DefaultHasher::new();
850 "layout_node".hash(&mut hasher);
851 hasher.finish()
852}
853
854#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
857pub struct DefaultLayoutPolicy;
858
859impl LayoutPolicy for DefaultLayoutPolicy {
860 fn measure(&self, scope: &MeasureScope<'_>) -> Result<LayoutResult, MeasurementError> {
861 let children = scope.children();
862 if children.is_empty() {
863 return Ok(LayoutResult::new(ComputedData::min_from_constraint(
864 scope.parent_constraint().as_ref(),
865 )));
866 }
867
868 let mut result = LayoutResult::new(ComputedData::ZERO);
869 let mut final_width = Px(0);
870 let mut final_height = Px(0);
871 for child in children {
872 let measurement = child.measure(scope.parent_constraint().as_ref())?;
873 result.place_child(measurement, PxPosition::ZERO);
874 let size = measurement.size();
875 final_width = final_width.max(size.width);
876 final_height = final_height.max(size.height);
877 }
878
879 result.size = ComputedData {
880 width: final_width,
881 height: final_height,
882 };
883 Ok(result)
884 }
885}
886
887#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
889pub struct NoopRenderPolicy;
890
891impl RenderPolicy for NoopRenderPolicy {}