1use std::{
8 any::Any,
9 collections::HashMap,
10 hash::{Hash, Hasher},
11 sync::Arc,
12};
13
14use crate::{
15 ComputedData, Constraint, MeasurementError, ParentConstraint, Px, RenderSlot,
16 component_tree::{
17 ComponentNodeMetaData, ComponentNodeMetaDatas, ComponentNodeTree, DrawLayoutBounds,
18 LayoutContext, LayoutDiagnosticsCollector, LayoutSnapshotMap, measure_node,
19 },
20 modifier::{
21 DrawModifierContent, DrawModifierContext, DrawModifierNode, LayoutModifierNode, Modifier,
22 },
23 px::PxPosition,
24 render_graph::RenderFragment,
25 runtime::configure_layout_node,
26 tessera,
27};
28
29#[derive(Clone, Copy, PartialEq)]
30pub(crate) struct ChildMeasure {
31 pub constraint: Constraint,
32 pub size: ComputedData,
33 pub consistent: bool,
34 pub consumed_insets: crate::Insets,
35}
36
37pub(crate) struct ChildProbe {
38 consumed_insets: crate::Insets,
39 constraint: Constraint,
40 size: ComputedData,
41}
42
43pub struct LayoutInput<'a> {
45 tree: &'a ComponentNodeTree,
46 parent_constraint: ParentConstraint<'a>,
47 children_ids: &'a [crate::NodeId],
48 layout_ctx: Option<&'a LayoutContext<'a>>,
49 measured_children: HashMap<crate::NodeId, ChildMeasure>,
50 probes: HashMap<crate::NodeId, ChildProbe>,
51 intrinsic_dependencies: bool,
52}
53
54#[derive(Clone, Copy)]
56pub struct LayoutChild {
57 node_id: crate::NodeId,
58 instance_key: u64,
59 index: usize,
60}
61
62impl PartialEq for LayoutChild {
63 fn eq(&self, other: &Self) -> bool {
64 self.node_id == other.node_id
65 }
66}
67
68impl Eq for LayoutChild {}
69
70impl Hash for LayoutChild {
71 fn hash<H: Hasher>(&self, state: &mut H) {
72 self.node_id.hash(state);
73 }
74}
75
76impl LayoutChild {
77 pub fn measure(
82 &self,
83 scope: &mut MeasureScope<'_>,
84 constraint: &Constraint,
85 ) -> Result<MeasuredChild, MeasurementError> {
86 scope.measure_child(self.index, constraint, true)
87 }
88
89 pub fn probe(
96 &self,
97 scope: &mut MeasureScope<'_>,
98 constraint: &Constraint,
99 ) -> Result<MeasuredChild, MeasurementError> {
100 scope.measure_child(self.index, constraint, false)
101 }
102
103 pub fn probe_intrinsic(
111 &self,
112 scope: &mut MeasureScope<'_>,
113 constraint: &Constraint,
114 ) -> Result<MeasuredChild, MeasurementError> {
115 *scope.intrinsic_dependencies = true;
116 if scope.is_intrinsic() {
117 return scope.measure_child(self.index, constraint, false);
118 }
119 let mut metadatas = ComponentNodeMetaDatas::new();
120 let mut snapshots = LayoutSnapshotMap::default();
121 let mut diagnostics = LayoutDiagnosticsCollector::default();
122 let consumed_insets = std::cell::Cell::new(
123 scope
124 .layout_ctx
125 .map_or_else(Default::default, |context| context.consumed_insets.get()),
126 );
127 let context = LayoutContext::intrinsic_probe(
128 &consumed_insets,
129 &mut snapshots,
130 &mut diagnostics,
131 scope.layout_ctx,
132 );
133 let size = measure_node(
134 self.node_id,
135 constraint,
136 scope.tree,
137 &mut metadatas,
138 Some(&context),
139 )?;
140 Ok(MeasuredChild {
141 instance_key: self.instance_key,
142 width: size.width,
143 height: size.height,
144 })
145 }
146
147 pub fn parent_data<T>(&self, scope: &MeasureScope<'_>) -> Option<T>
149 where
150 T: Clone + Send + Sync + 'static,
151 {
152 let node = scope.tree.get(self.node_id)?;
153 node.get().modifier.parent_data()
154 }
155
156 pub(crate) const fn instance_key(&self) -> u64 {
157 self.instance_key
158 }
159}
160
161#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
163pub struct MeasuredChild {
164 instance_key: u64,
165 pub width: Px,
167 pub height: Px,
169}
170
171impl MeasuredChild {
172 pub const fn size(&self) -> ComputedData {
174 ComputedData {
175 width: self.width,
176 height: self.height,
177 }
178 }
179
180 pub(crate) const fn instance_key(&self) -> u64 {
181 self.instance_key
182 }
183}
184
185#[derive(Clone, Copy)]
187pub struct PlacementChild<'a> {
188 node_id: crate::NodeId,
189 instance_key: u64,
190 tree: &'a ComponentNodeTree,
191 size: ComputedData,
192}
193
194impl<'a> PlacementChild<'a> {
195 pub const fn size(&self) -> ComputedData {
197 self.size
198 }
199
200 pub fn parent_data<T>(&self) -> Option<T>
202 where
203 T: Clone + Send + Sync + 'static,
204 {
205 let node = self.tree.get(self.node_id)?;
206 node.get().modifier.parent_data()
207 }
208
209 pub(crate) const fn instance_key(&self) -> u64 {
210 self.instance_key
211 }
212}
213
214pub struct MeasureScope<'a> {
216 tree: &'a ComponentNodeTree,
217 metadatas: &'a mut ComponentNodeMetaDatas,
218 layout_ctx: Option<&'a LayoutContext<'a>>,
219 measured_children: &'a mut HashMap<crate::NodeId, ChildMeasure>,
220 probes: &'a mut HashMap<crate::NodeId, ChildProbe>,
221 intrinsic_dependencies: &'a mut bool,
222 parent_constraint: ParentConstraint<'a>,
223 children_ids: &'a [crate::NodeId],
224}
225
226impl<'a> MeasureScope<'a> {
227 pub(crate) fn new(
228 tree: &'a ComponentNodeTree,
229 metadatas: &'a mut ComponentNodeMetaDatas,
230 layout_ctx: Option<&'a LayoutContext<'a>>,
231 measured_children: &'a mut HashMap<crate::NodeId, ChildMeasure>,
232 probes: &'a mut HashMap<crate::NodeId, ChildProbe>,
233 intrinsic_dependencies: &'a mut bool,
234 parent_constraint: ParentConstraint<'a>,
235 children_ids: &'a [crate::NodeId],
236 ) -> Self {
237 Self {
238 tree,
239 metadatas,
240 layout_ctx,
241 measured_children,
242 probes,
243 intrinsic_dependencies,
244 parent_constraint,
245 children_ids,
246 }
247 }
248
249 pub const fn parent_constraint(&self) -> ParentConstraint<'a> {
251 self.parent_constraint
252 }
253
254 pub fn placement<R>(&self, calculate: impl FnOnce() -> R) -> R {
262 let _phase = crate::runtime::push_phase(crate::runtime::RuntimePhase::Place);
263 calculate()
264 }
265
266 pub fn is_intrinsic(&self) -> bool {
268 self.layout_ctx.is_some_and(|context| context.intrinsic)
269 }
270
271 pub fn children(&self) -> Vec<LayoutChild> {
274 self.children_ids
275 .iter()
276 .enumerate()
277 .map(|(index, &node_id)| {
278 let instance_key = self
279 .tree
280 .get(node_id)
281 .unwrap_or_else(|| {
282 let owner = crate::runtime::current_node_id();
283 let ancestry = owner
284 .into_iter()
285 .flat_map(|id| id.ancestors(self.tree))
286 .map(|id| (id, self.tree[id].get().fn_name))
287 .collect::<Vec<_>>();
288 panic!(
289 "Direct child layout node must exist: child={node_id:?}, owner={owner:?}, ancestry={ancestry:?}"
290 )
291 })
292 .get()
293 .instance_key;
294 LayoutChild {
295 node_id,
296 instance_key,
297 index,
298 }
299 })
300 .collect()
301 }
302
303 pub(crate) fn measure_at(
304 &mut self,
305 index: usize,
306 constraint: &Constraint,
307 ) -> Result<MeasuredChild, MeasurementError> {
308 self.measure_child(index, constraint, true)
309 }
310
311 fn measure_child(
312 &mut self,
313 index: usize,
314 constraint: &Constraint,
315 record: bool,
316 ) -> Result<MeasuredChild, MeasurementError> {
317 let node_id = *self
318 .children_ids
319 .get(index)
320 .expect("Layout child index must refer to a direct child");
321 let instance_key = self
322 .tree
323 .get(node_id)
324 .expect("Direct child layout node must exist")
325 .get()
326 .instance_key;
327
328 let consumed_insets = self
329 .layout_ctx
330 .map_or_else(Default::default, |context| context.consumed_insets.get());
331 if let Some(probe) = self.probes.get(&node_id) {
332 if probe.constraint == *constraint && probe.consumed_insets == consumed_insets {
333 let size = probe.size;
334 if record {
335 self.record_measure(node_id, *constraint, size);
336 }
337 return Ok(MeasuredChild {
338 instance_key,
339 width: size.width,
340 height: size.height,
341 });
342 }
343 }
344
345 let size = measure_node(
346 node_id,
347 constraint,
348 self.tree,
349 self.metadatas,
350 self.layout_ctx,
351 )?;
352 self.probes.insert(
353 node_id,
354 ChildProbe {
355 consumed_insets,
356 constraint: *constraint,
357 size,
358 },
359 );
360 if record {
361 self.record_measure(node_id, *constraint, size);
362 }
363 Ok(MeasuredChild {
364 instance_key,
365 width: size.width,
366 height: size.height,
367 })
368 }
369
370 fn record_measure(
371 &mut self,
372 node_id: crate::NodeId,
373 constraint: Constraint,
374 size: ComputedData,
375 ) {
376 let consumed_insets = self
377 .layout_ctx
378 .map_or_else(Default::default, |context| context.consumed_insets.get());
379 if let Some(entry) = self.measured_children.get_mut(&node_id) {
380 let consistent = entry.consistent
381 && entry.constraint == constraint
382 && entry.size == size
383 && entry.consumed_insets == consumed_insets;
384 entry.constraint = constraint;
385 entry.size = size;
386 entry.consistent = consistent;
387 entry.consumed_insets = consumed_insets;
388 } else {
389 self.measured_children.insert(
390 node_id,
391 ChildMeasure {
392 consumed_insets,
393 constraint,
394 size,
395 consistent: true,
396 },
397 );
398 }
399 }
400}
401
402pub struct PlacementScope<'a> {
404 tree: &'a ComponentNodeTree,
405 parent_constraint: ParentConstraint<'a>,
406 children_ids: &'a [crate::NodeId],
407 child_sizes: &'a HashMap<crate::NodeId, ComputedData>,
408 size: ComputedData,
409}
410
411impl<'a> PlacementScope<'a> {
412 pub(crate) fn new(
413 tree: &'a ComponentNodeTree,
414 parent_constraint: ParentConstraint<'a>,
415 children_ids: &'a [crate::NodeId],
416 child_sizes: &'a HashMap<crate::NodeId, ComputedData>,
417 size: ComputedData,
418 ) -> Self {
419 Self {
420 tree,
421 parent_constraint,
422 children_ids,
423 child_sizes,
424 size,
425 }
426 }
427
428 pub const fn parent_constraint(&self) -> ParentConstraint<'a> {
430 self.parent_constraint
431 }
432
433 pub fn children(&self) -> Vec<PlacementChild<'_>> {
435 self.children_ids
436 .iter()
437 .map(|&node_id| {
438 let node = self
439 .tree
440 .get(node_id)
441 .expect("Direct child layout node must exist");
442 PlacementChild {
443 node_id,
444 instance_key: node.get().instance_key,
445 tree: self.tree,
446 size: self
447 .child_sizes
448 .get(&node_id)
449 .copied()
450 .expect("Placement child size must exist for a direct child layout node"),
451 }
452 })
453 .collect()
454 }
455
456 pub const fn size(&self) -> ComputedData {
458 self.size
459 }
460}
461
462impl<'a> LayoutInput<'a> {
463 pub fn consumed_window_insets(&self) -> crate::Insets {
465 self.layout_ctx
466 .map_or_else(Default::default, |context| context.consumed_insets.get())
467 }
468
469 pub fn with_consumed_window_insets<R>(
472 &self,
473 insets: crate::Insets,
474 measure: impl FnOnce() -> R,
475 ) -> R {
476 if let Some(context) = self.layout_ctx {
477 context.with_consumed_insets(self.consumed_window_insets().union(insets), measure)
478 } else {
479 measure()
480 }
481 }
482
483 pub(crate) fn new(
484 tree: &'a ComponentNodeTree,
485 parent_constraint: ParentConstraint<'a>,
486 children_ids: &'a [crate::NodeId],
487 layout_ctx: Option<&'a LayoutContext<'a>>,
488 ) -> Self {
489 Self {
490 tree,
491 parent_constraint,
492 children_ids,
493 layout_ctx,
494 measured_children: HashMap::new(),
495 probes: HashMap::new(),
496 intrinsic_dependencies: false,
497 }
498 }
499
500 pub const fn parent_constraint(&self) -> ParentConstraint<'a> {
502 self.parent_constraint
503 }
504
505 pub fn is_intrinsic(&self) -> bool {
507 self.layout_ctx.is_some_and(|context| context.intrinsic)
508 }
509
510 pub(crate) fn take_measured_children(&mut self) -> HashMap<crate::NodeId, ChildMeasure> {
511 std::mem::take(&mut self.measured_children)
512 }
513
514 pub(crate) fn has_intrinsic_dependencies(&self) -> bool {
515 self.intrinsic_dependencies
516 }
517
518 pub(crate) fn extend_measured_children(
519 &mut self,
520 children: HashMap<crate::NodeId, ChildMeasure>,
521 ) {
522 for (child_id, measurement) in children {
523 if let Some(entry) = self.measured_children.get_mut(&child_id) {
524 let consistent = entry.consistent
525 && entry.constraint == measurement.constraint
526 && entry.size == measurement.size
527 && entry.consumed_insets == measurement.consumed_insets
528 && measurement.consistent;
529 entry.constraint = measurement.constraint;
530 entry.size = measurement.size;
531 entry.consumed_insets = measurement.consumed_insets;
532 entry.consistent = consistent;
533 } else {
534 self.measured_children.insert(child_id, measurement);
535 }
536 }
537 }
538
539 pub(crate) fn measure_scope<'s>(
540 &'s mut self,
541 metadatas: &'s mut ComponentNodeMetaDatas,
542 ) -> MeasureScope<'s> {
543 MeasureScope::new(
544 self.tree,
545 metadatas,
546 self.layout_ctx,
547 &mut self.measured_children,
548 &mut self.probes,
549 &mut self.intrinsic_dependencies,
550 self.parent_constraint,
551 self.children_ids,
552 )
553 }
554
555 pub fn children(&self) -> Vec<LayoutChild> {
557 self.children_ids
558 .iter()
559 .enumerate()
560 .map(|(index, &node_id)| {
561 let instance_key = self
562 .tree
563 .get(node_id)
564 .expect("Direct child layout node must exist")
565 .get()
566 .instance_key;
567 LayoutChild {
568 node_id,
569 instance_key,
570 index,
571 }
572 })
573 .collect()
574 }
575}
576
577#[derive(Clone)]
579pub struct LayoutResult {
580 pub size: ComputedData,
582 pub placements: Vec<(u64, PxPosition)>,
584}
585
586impl LayoutResult {
587 pub const fn new(size: ComputedData) -> Self {
589 Self {
590 size,
591 placements: Vec::new(),
592 }
593 }
594
595 pub fn place_child<T>(&mut self, child: T, position: PxPosition)
597 where
598 T: LayoutPlacementTarget,
599 {
600 self.place(child.instance_key(), position);
601 }
602
603 pub fn place(&mut self, instance_key: u64, position: PxPosition) {
605 self.placements.push((instance_key, position));
606 }
607
608 pub const fn with_size(mut self, size: ComputedData) -> Self {
610 self.size = size;
611 self
612 }
613
614 pub fn into_placements(self) -> Vec<(u64, PxPosition)> {
616 self.placements
617 }
618
619 pub fn into_placement_result(self) -> PlacementResult {
621 PlacementResult {
622 placements: self.placements,
623 }
624 }
625}
626
627#[derive(Clone, Debug, Default, PartialEq)]
629pub struct PlacementResult {
630 placements: Vec<(u64, PxPosition)>,
631}
632
633impl PlacementResult {
634 pub const fn new() -> Self {
636 Self {
637 placements: Vec::new(),
638 }
639 }
640
641 pub fn from_placements(placements: Vec<(u64, PxPosition)>) -> Self {
643 Self { placements }
644 }
645
646 pub fn place(&mut self, instance_key: u64, position: PxPosition) {
648 self.placements.push((instance_key, position));
649 }
650
651 pub fn is_empty(&self) -> bool {
653 self.placements.is_empty()
654 }
655
656 pub fn len(&self) -> usize {
658 self.placements.len()
659 }
660
661 pub fn items(&self) -> &[(u64, PxPosition)] {
663 &self.placements
664 }
665
666 pub fn iter(&self) -> std::slice::Iter<'_, (u64, PxPosition)> {
668 self.placements.iter()
669 }
670
671 pub fn into_placements(self) -> Vec<(u64, PxPosition)> {
673 self.placements
674 }
675}
676
677impl Default for LayoutResult {
678 fn default() -> Self {
679 Self::new(ComputedData::ZERO)
680 }
681}
682
683pub trait LayoutPlacementTarget: Copy {
685 #[doc(hidden)]
686 fn instance_key(&self) -> u64;
687}
688
689impl LayoutPlacementTarget for LayoutChild {
690 fn instance_key(&self) -> u64 {
691 self.instance_key()
692 }
693}
694
695impl LayoutPlacementTarget for MeasuredChild {
696 fn instance_key(&self) -> u64 {
697 self.instance_key()
698 }
699}
700
701impl LayoutPlacementTarget for PlacementChild<'_> {
702 fn instance_key(&self) -> u64 {
703 self.instance_key()
704 }
705}
706
707pub struct RenderInput<'a> {
709 current_node_id: crate::NodeId,
710 metadatas: &'a mut ComponentNodeMetaDatas,
711 pub(crate) draw_bounds: DrawLayoutBounds,
712}
713
714impl<'a> RenderInput<'a> {
715 pub(crate) fn new(
716 current_node_id: crate::NodeId,
717 metadatas: &'a mut ComponentNodeMetaDatas,
718 ) -> Self {
719 let size = metadatas
720 .get(¤t_node_id)
721 .and_then(|metadata| metadata.computed_data)
722 .unwrap_or(ComputedData::ZERO);
723 Self {
724 current_node_id,
725 metadatas,
726 draw_bounds: DrawLayoutBounds {
727 position: PxPosition::ZERO,
728 size,
729 },
730 }
731 }
732
733 pub fn metadata_mut(&mut self) -> RenderMetadataMut<'_> {
735 let metadata = self
736 .metadatas
737 .get_mut(&self.current_node_id)
738 .expect("Metadata for current node must exist during record");
739 RenderMetadataMut {
740 metadata,
741 draw_bounds: self.draw_bounds,
742 }
743 }
744
745 pub(crate) fn recorded_op_count(&self) -> usize {
746 self.metadatas
747 .get(&self.current_node_id)
748 .expect("record metadata")
749 .fragment
750 .ops()
751 .len()
752 }
753
754 pub(crate) fn draw_layers(&self) -> &[Option<DrawLayoutBounds>] {
755 self.metadatas
756 .get(&self.current_node_id)
757 .expect("record metadata")
758 .draw_layout
759 .layers
760 .as_deref()
761 .unwrap_or_default()
762 }
763
764 pub(crate) fn finish_draw_range(&mut self, start: usize, bounds: DrawLayoutBounds) {
765 let metadata = self
766 .metadatas
767 .get_mut(&self.current_node_id)
768 .expect("record metadata");
769 for op in metadata.fragment.ops_mut().iter_mut().skip(start) {
770 op.position_override =
771 Some(bounds.position + op.position_override.unwrap_or(PxPosition::ZERO));
772 op.size_override.get_or_insert(bounds.size.into());
773 }
774 }
775}
776
777pub struct RenderMetadataMut<'a> {
779 metadata: &'a mut ComponentNodeMetaData,
780 draw_bounds: DrawLayoutBounds,
781}
782
783impl RenderMetadataMut<'_> {
784 pub fn computed_data(&self) -> Option<ComputedData> {
786 self.metadata.computed_data.map(|_| self.draw_bounds.size)
787 }
788
789 pub fn fragment_mut(&mut self) -> &mut RenderFragment {
791 self.metadata.fragment_mut()
792 }
793
794 pub fn set_clips_children(&mut self, clips_children: bool) {
796 self.metadata.clips_children = clips_children;
797 if clips_children
798 && self.metadata.clip_region().is_none()
799 && (self.draw_bounds.position != PxPosition::ZERO
800 || self.metadata.computed_data != Some(self.draw_bounds.size))
801 {
802 self.set_clip_shape(crate::ClipShape::RoundedRectangle {
803 radii: [0.0; 4],
804 exponents: [2.0; 4],
805 });
806 }
807 }
808
809 pub fn set_clip_shape(&mut self, shape: crate::ClipShape) {
811 self.metadata.clips_children = true;
812 let size = self
813 .computed_data()
814 .expect("shape clipping requires measured bounds");
815 self.metadata.set_clip_region(Some(crate::ClipRegion {
816 position: self.draw_bounds.position,
817 size: [size.width.to_f32(), size.height.to_f32()],
818 shape,
819 }));
820 }
821
822 pub fn set_clip_region(&mut self, mut region: crate::ClipRegion) {
825 self.metadata.clips_children = true;
826 region.position = region.position + self.draw_bounds.position;
827 self.metadata.set_clip_region(Some(region));
828 }
829
830 pub fn multiply_opacity(&mut self, opacity: f32) {
832 self.metadata.opacity *= opacity;
833 }
834}
835
836#[doc(hidden)]
838pub trait LayoutModifierDyn: Send + Sync {
839 fn as_any(&self) -> &dyn Any;
841 fn measure_dyn(&self, scope: &mut MeasureScope<'_>) -> Result<LayoutResult, MeasurementError>;
843 fn place_children_dyn(
845 &self,
846 scope: &PlacementScope<'_>,
847 inner: &PlacementResult,
848 ) -> Option<PlacementResult>;
849 fn dyn_eq(&self, other: &dyn LayoutModifierDyn) -> bool;
851 fn dyn_measure_eq(&self, other: &dyn LayoutModifierDyn) -> bool;
853 fn dyn_placement_eq(&self, other: &dyn LayoutModifierDyn) -> bool;
855 fn clone_box(&self) -> Box<dyn LayoutModifierDyn>;
857}
858
859impl<T> LayoutModifierDyn for T
860where
861 T: LayoutModifierNode + Clone + PartialEq,
862{
863 fn as_any(&self) -> &dyn Any {
864 self
865 }
866
867 fn measure_dyn(&self, scope: &mut MeasureScope<'_>) -> Result<LayoutResult, MeasurementError> {
868 crate::work::record_policy::<T>(if scope.is_intrinsic() {
869 crate::WorkPhase::IntrinsicMeasure
870 } else {
871 crate::WorkPhase::Measure
872 });
873 LayoutModifierNode::measure(self, scope)
874 }
875
876 fn place_children_dyn(
877 &self,
878 scope: &PlacementScope<'_>,
879 inner: &PlacementResult,
880 ) -> Option<PlacementResult> {
881 crate::work::record_policy::<T>(crate::WorkPhase::Place);
882 LayoutModifierNode::place_children(self, scope, inner)
883 }
884
885 fn dyn_eq(&self, other: &dyn LayoutModifierDyn) -> bool {
886 other
887 .as_any()
888 .downcast_ref::<T>()
889 .is_some_and(|other| self == other)
890 }
891
892 fn dyn_measure_eq(&self, other: &dyn LayoutModifierDyn) -> bool {
893 other
894 .as_any()
895 .downcast_ref::<T>()
896 .is_some_and(|other| LayoutModifierNode::measure_eq(self, other))
897 }
898
899 fn dyn_placement_eq(&self, other: &dyn LayoutModifierDyn) -> bool {
900 other
901 .as_any()
902 .downcast_ref::<T>()
903 .is_some_and(|other| LayoutModifierNode::placement_eq(self, other))
904 }
905
906 fn clone_box(&self) -> Box<dyn LayoutModifierDyn> {
907 Box::new(self.clone())
908 }
909}
910
911impl Clone for Box<dyn LayoutModifierDyn> {
912 fn clone(&self) -> Self {
913 self.clone_box()
914 }
915}
916
917#[derive(Clone, Default)]
923pub struct LayoutModifierHandle {
924 node: Option<Arc<dyn LayoutModifierDyn>>,
925}
926
927impl LayoutModifierHandle {
928 pub(crate) fn as_policy(&self) -> &dyn LayoutModifierDyn {
929 self.node.as_deref().unwrap_or(&DefaultLayoutNode)
930 }
931}
932
933impl PartialEq for LayoutModifierHandle {
934 fn eq(&self, other: &Self) -> bool {
935 self.as_policy().dyn_eq(other.as_policy())
936 }
937}
938
939impl<S> From<S> for LayoutModifierHandle
940where
941 S: LayoutModifierNode + Clone + PartialEq,
942{
943 fn from(node: S) -> Self {
944 Self {
945 node: Some(Arc::new(node)),
946 }
947 }
948}
949
950#[derive(Clone)]
956pub struct DrawModifierHandle {
957 node: Box<dyn ErasedDrawModifierNode>,
958}
959
960impl DrawModifierHandle {
961 pub(crate) fn into_node(self) -> Box<dyn DrawModifierNode> {
962 self.node.into_node()
963 }
964}
965
966impl Default for DrawModifierHandle {
967 fn default() -> Self {
968 Self {
969 node: Box::new(NoopDrawModifier),
970 }
971 }
972}
973
974impl PartialEq for DrawModifierHandle {
975 fn eq(&self, other: &Self) -> bool {
976 self.node.dyn_eq(other.node.as_ref())
977 }
978}
979
980impl<N> From<N> for DrawModifierHandle
981where
982 N: DrawModifierNode + Clone + PartialEq,
983{
984 fn from(node: N) -> Self {
985 Self {
986 node: Box::new(node),
987 }
988 }
989}
990
991trait ErasedDrawModifierNode: Send + Sync {
993 fn as_any(&self) -> &dyn Any;
994 fn into_node(self: Box<Self>) -> Box<dyn DrawModifierNode>;
995 fn dyn_eq(&self, other: &dyn ErasedDrawModifierNode) -> bool;
996 fn clone_box(&self) -> Box<dyn ErasedDrawModifierNode>;
997}
998
999impl<N> ErasedDrawModifierNode for N
1000where
1001 N: DrawModifierNode + Clone + PartialEq,
1002{
1003 fn as_any(&self) -> &dyn Any {
1004 self
1005 }
1006
1007 fn into_node(self: Box<Self>) -> Box<dyn DrawModifierNode> {
1008 self
1009 }
1010
1011 fn dyn_eq(&self, other: &dyn ErasedDrawModifierNode) -> bool {
1012 other
1013 .as_any()
1014 .downcast_ref::<N>()
1015 .is_some_and(|other| self == other)
1016 }
1017
1018 fn clone_box(&self) -> Box<dyn ErasedDrawModifierNode> {
1019 Box::new(self.clone())
1020 }
1021}
1022
1023impl Clone for Box<dyn ErasedDrawModifierNode> {
1024 fn clone(&self) -> Self {
1025 self.clone_box()
1026 }
1027}
1028
1029#[tessera(crate, layout)]
1067pub fn layout(
1068 #[prop(into)] policy: Option<LayoutModifierHandle>,
1069 #[prop(into)] draw: Option<DrawModifierHandle>,
1070 modifier: Option<Modifier>,
1071 child: Option<RenderSlot>,
1072) {
1073 configure_layout_node(
1074 policy.unwrap_or_default(),
1075 draw.unwrap_or_default(),
1076 modifier.unwrap_or_default(),
1077 );
1078 if let Some(child) = child {
1079 child.render();
1080 }
1081}
1082
1083#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
1086pub struct DefaultLayoutNode;
1087
1088impl LayoutModifierNode for DefaultLayoutNode {
1089 fn measure(&self, scope: &mut MeasureScope<'_>) -> Result<LayoutResult, MeasurementError> {
1090 let child_count = scope.children().len();
1091 if child_count == 0 {
1092 return Ok(LayoutResult::new(ComputedData::min_from_constraint(
1093 scope.parent_constraint().as_ref(),
1094 )));
1095 }
1096
1097 let mut result = LayoutResult::new(ComputedData::ZERO);
1098 let mut final_width = Px(0);
1099 let mut final_height = Px(0);
1100 let constraint = *scope.parent_constraint().as_ref();
1101 for index in 0..child_count {
1102 let measurement = scope.measure_at(index, &constraint)?;
1103 result.place_child(measurement, PxPosition::ZERO);
1104 let size = measurement.size();
1105 final_width = final_width.max(size.width);
1106 final_height = final_height.max(size.height);
1107 }
1108
1109 result.size = ComputedData {
1110 width: final_width,
1111 height: final_height,
1112 };
1113 Ok(result)
1114 }
1115
1116 fn place_children(
1117 &self,
1118 scope: &PlacementScope<'_>,
1119 _inner: &PlacementResult,
1120 ) -> Option<PlacementResult> {
1121 let mut result = PlacementResult::new();
1124 for child in scope.children() {
1125 result.place(child.instance_key(), PxPosition::ZERO);
1126 }
1127 Some(result)
1128 }
1129}
1130
1131#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
1133pub struct NoopDrawModifier;
1134
1135impl DrawModifierNode for NoopDrawModifier {
1136 fn draw(&self, ctx: &mut DrawModifierContext<'_, '_>, content: &mut dyn DrawModifierContent) {
1137 content.draw(ctx.render_input);
1138 }
1139}