1use std::{
4 any::{Any, TypeId},
5 cell::RefCell,
6 collections::HashMap,
7 sync::Arc,
8};
9
10use parking_lot::RwLock;
11
12use crate::{
13 ComputeResourceManager, ComputedData, Constraint, MeasurementError, ParentConstraint, Px,
14 RenderSlot,
15 component_tree::{
16 ComponentNodeMetaDatas, ComponentNodeTree, LayoutContext, measure_node, measure_nodes,
17 },
18 modifier::{Modifier, ParentDataMap},
19 prop::Prop,
20 px::PxPosition,
21 render_graph::RenderFragment,
22 runtime::TesseraRuntime,
23 tessera,
24};
25
26#[derive(Clone, Copy)]
27pub(crate) struct ChildMeasure {
28 pub constraint: Constraint,
29 pub size: ComputedData,
30 pub consistent: bool,
31}
32
33pub struct LayoutInput<'a> {
35 tree: &'a ComponentNodeTree,
36 parent_constraint: ParentConstraint<'a>,
37 children_ids: &'a [crate::NodeId],
38 metadatas: &'a ComponentNodeMetaDatas,
39 layout_ctx: Option<&'a LayoutContext<'a>>,
40 measured_children: RefCell<HashMap<crate::NodeId, ChildMeasure>>,
41}
42
43impl<'a> LayoutInput<'a> {
44 pub(crate) fn new(
45 tree: &'a ComponentNodeTree,
46 parent_constraint: ParentConstraint<'a>,
47 children_ids: &'a [crate::NodeId],
48 metadatas: &'a ComponentNodeMetaDatas,
49 layout_ctx: Option<&'a LayoutContext<'a>>,
50 ) -> Self {
51 Self {
52 tree,
53 parent_constraint,
54 children_ids,
55 metadatas,
56 layout_ctx,
57 measured_children: RefCell::new(HashMap::new()),
58 }
59 }
60
61 pub const fn parent_constraint(&self) -> ParentConstraint<'a> {
63 self.parent_constraint
64 }
65
66 pub fn children_ids(&self) -> &'a [crate::NodeId] {
68 self.children_ids
69 }
70
71 pub(crate) fn take_measured_children(&self) -> HashMap<crate::NodeId, ChildMeasure> {
72 std::mem::take(&mut *self.measured_children.borrow_mut())
73 }
74
75 pub(crate) fn extend_measured_children(&self, children: HashMap<crate::NodeId, ChildMeasure>) {
76 let mut measured_children = self.measured_children.borrow_mut();
77 for (child_id, measurement) in children {
78 if let Some(entry) = measured_children.get_mut(&child_id) {
79 let consistent = entry.consistent
80 && entry.constraint == measurement.constraint
81 && entry.size == measurement.size
82 && measurement.consistent;
83 entry.constraint = measurement.constraint;
84 entry.size = measurement.size;
85 entry.consistent = consistent;
86 } else {
87 measured_children.insert(child_id, measurement);
88 }
89 }
90 }
91
92 fn record_child_measure(
93 &self,
94 child_id: crate::NodeId,
95 constraint: Constraint,
96 size: ComputedData,
97 ) {
98 let mut measured_children = self.measured_children.borrow_mut();
99 if let Some(entry) = measured_children.get_mut(&child_id) {
100 let consistent =
101 entry.consistent && entry.constraint == constraint && entry.size == size;
102 entry.constraint = constraint;
103 entry.size = size;
104 entry.consistent = consistent;
105 } else {
106 measured_children.insert(
107 child_id,
108 ChildMeasure {
109 constraint,
110 size,
111 consistent: true,
112 },
113 );
114 }
115 }
116
117 pub fn measure_children(
119 &self,
120 nodes_to_measure: Vec<(crate::NodeId, Constraint)>,
121 ) -> Result<HashMap<crate::NodeId, ComputedData>, MeasurementError> {
122 let constraints: HashMap<crate::NodeId, Constraint> = nodes_to_measure
123 .iter()
124 .map(|(child_id, constraint)| (*child_id, *constraint))
125 .collect();
126 let results = measure_nodes(nodes_to_measure, self.tree, self.metadatas, self.layout_ctx);
127
128 let mut successful_results = HashMap::new();
129 for (child_id, result) in results {
130 match result {
131 Ok(size) => {
132 if let Some(constraint) = constraints.get(&child_id) {
133 self.record_child_measure(child_id, *constraint, size);
134 }
135 successful_results.insert(child_id, size);
136 }
137 Err(e) => {
138 return Err(e);
139 }
140 };
141 }
142 Ok(successful_results)
143 }
144
145 pub fn measure_children_untracked(
147 &self,
148 nodes_to_measure: Vec<(crate::NodeId, Constraint)>,
149 ) -> Result<HashMap<crate::NodeId, ComputedData>, MeasurementError> {
150 let results = measure_nodes(nodes_to_measure, self.tree, self.metadatas, self.layout_ctx);
151
152 let mut successful_results = HashMap::new();
153 for (child_id, result) in results {
154 match result {
155 Ok(size) => {
156 successful_results.insert(child_id, size);
157 }
158 Err(e) => {
159 return Err(e);
160 }
161 };
162 }
163 Ok(successful_results)
164 }
165
166 pub fn measure_child(
168 &self,
169 child_id: crate::NodeId,
170 constraint: &Constraint,
171 ) -> Result<ComputedData, MeasurementError> {
172 let size = measure_node(
173 child_id,
174 constraint,
175 self.tree,
176 self.metadatas,
177 self.layout_ctx,
178 )?;
179 self.record_child_measure(child_id, *constraint, size);
180 Ok(size)
181 }
182
183 pub fn measure_child_untracked(
185 &self,
186 child_id: crate::NodeId,
187 constraint: &Constraint,
188 ) -> Result<ComputedData, MeasurementError> {
189 measure_node(
190 child_id,
191 constraint,
192 self.tree,
193 self.metadatas,
194 self.layout_ctx,
195 )
196 }
197
198 pub fn measure_child_in_parent_constraint(
200 &self,
201 child_id: crate::NodeId,
202 ) -> Result<ComputedData, MeasurementError> {
203 self.measure_child(child_id, self.parent_constraint.as_ref())
204 }
205
206 pub fn child_parent_data<T>(&self, child_id: crate::NodeId) -> Option<T>
208 where
209 T: Clone + Send + Sync + 'static,
210 {
211 let node = self.tree.get(child_id)?;
212 let mut data: ParentDataMap = HashMap::default();
213 node.get().modifier.apply_parent_data(&mut data);
214 let value = data.get(&TypeId::of::<T>())?;
215 value.downcast_ref::<T>().cloned()
216 }
217}
218
219pub struct PlacementInput<'a> {
221 tree: &'a ComponentNodeTree,
222 parent_constraint: ParentConstraint<'a>,
223 children_ids: &'a [crate::NodeId],
224 child_sizes: &'a HashMap<crate::NodeId, ComputedData>,
225 size: ComputedData,
226}
227
228impl<'a> PlacementInput<'a> {
229 pub(crate) fn new(
230 tree: &'a ComponentNodeTree,
231 parent_constraint: ParentConstraint<'a>,
232 children_ids: &'a [crate::NodeId],
233 child_sizes: &'a HashMap<crate::NodeId, ComputedData>,
234 size: ComputedData,
235 ) -> Self {
236 Self {
237 tree,
238 parent_constraint,
239 children_ids,
240 child_sizes,
241 size,
242 }
243 }
244
245 pub const fn parent_constraint(&self) -> ParentConstraint<'a> {
247 self.parent_constraint
248 }
249
250 pub fn children_ids(&self) -> &'a [crate::NodeId] {
252 self.children_ids
253 }
254
255 pub fn child_size(&self, child_id: crate::NodeId) -> Option<ComputedData> {
258 self.child_sizes.get(&child_id).copied()
259 }
260
261 pub const fn size(&self) -> ComputedData {
263 self.size
264 }
265
266 pub fn child_parent_data<T>(&self, child_id: crate::NodeId) -> Option<T>
268 where
269 T: Clone + Send + Sync + 'static,
270 {
271 let node = self.tree.get(child_id)?;
272 let mut data: ParentDataMap = HashMap::default();
273 node.get().modifier.apply_parent_data(&mut data);
274 let value = data.get(&TypeId::of::<T>())?;
275 value.downcast_ref::<T>().cloned()
276 }
277}
278
279pub struct LayoutOutput<'a> {
281 placements: Vec<(u64, PxPosition)>,
282 resolve_instance_key: &'a dyn Fn(crate::NodeId) -> u64,
283}
284
285impl<'a> LayoutOutput<'a> {
286 pub(crate) fn new(resolve_instance_key: &'a dyn Fn(crate::NodeId) -> u64) -> Self {
287 Self {
288 placements: Vec::new(),
289 resolve_instance_key,
290 }
291 }
292
293 pub fn place_child(&mut self, child_id: crate::NodeId, position: PxPosition) {
295 let instance_key = (self.resolve_instance_key)(child_id);
296 self.placements.push((instance_key, position));
297 }
298
299 pub(crate) fn place_instance_key(&mut self, instance_key: u64, position: PxPosition) {
300 self.placements.push((instance_key, position));
301 }
302
303 pub(crate) fn finish(self) -> Vec<(u64, PxPosition)> {
304 self.placements
305 }
306}
307
308#[derive(Clone)]
310pub struct LayoutResult {
311 pub size: ComputedData,
313 pub placements: Vec<(u64, PxPosition)>,
315}
316
317pub struct RenderInput<'a> {
319 current_node_id: crate::NodeId,
320 metadatas: &'a ComponentNodeMetaDatas,
321 pub compute_resource_manager: Arc<RwLock<ComputeResourceManager>>,
323 pub gpu: &'a wgpu::Device,
325}
326
327impl<'a> RenderInput<'a> {
328 pub(crate) fn new(
329 current_node_id: crate::NodeId,
330 metadatas: &'a ComponentNodeMetaDatas,
331 compute_resource_manager: Arc<RwLock<ComputeResourceManager>>,
332 gpu: &'a wgpu::Device,
333 ) -> Self {
334 Self {
335 current_node_id,
336 metadatas,
337 compute_resource_manager,
338 gpu,
339 }
340 }
341
342 pub fn metadata_mut(&self) -> RenderMetadataMut<'_> {
344 let metadata = self
345 .metadatas
346 .get_mut(&self.current_node_id)
347 .expect("Metadata for current node must exist during record");
348 RenderMetadataMut { metadata }
349 }
350}
351
352pub struct RenderMetadataMut<'a> {
354 metadata: dashmap::mapref::one::RefMut<
355 'a,
356 crate::NodeId,
357 crate::component_tree::ComponentNodeMetaData,
358 >,
359}
360
361impl RenderMetadataMut<'_> {
362 pub fn computed_data(&self) -> Option<ComputedData> {
364 self.metadata.computed_data
365 }
366
367 pub fn fragment_mut(&mut self) -> &mut RenderFragment {
369 self.metadata.fragment_mut()
370 }
371
372 pub fn set_clips_children(&mut self, clips_children: bool) {
374 self.metadata.clips_children = clips_children;
375 }
376
377 pub fn multiply_opacity(&mut self, opacity: f32) {
379 self.metadata.opacity *= opacity;
380 }
381}
382
383pub trait LayoutPolicy: Send + Sync + Clone + PartialEq + 'static {
385 fn measure(
387 &self,
388 input: &LayoutInput<'_>,
389 output: &mut LayoutOutput<'_>,
390 ) -> Result<ComputedData, MeasurementError>;
391
392 fn measure_eq(&self, other: &Self) -> bool {
394 self == other
395 }
396
397 fn placement_eq(&self, other: &Self) -> bool {
399 self == other
400 }
401
402 fn place_children(&self, _input: &PlacementInput<'_>, _output: &mut LayoutOutput<'_>) -> bool {
407 false
408 }
409}
410
411pub trait RenderPolicy: Send + Sync + Clone + PartialEq + 'static {
413 fn record(&self, _input: &RenderInput<'_>) {}
415}
416
417#[doc(hidden)]
419pub trait LayoutPolicyDyn: Send + Sync {
420 fn as_any(&self) -> &dyn Any;
422 fn measure_dyn(
424 &self,
425 input: &LayoutInput<'_>,
426 output: &mut LayoutOutput<'_>,
427 ) -> Result<ComputedData, MeasurementError>;
428 fn place_children_dyn(&self, input: &PlacementInput<'_>, output: &mut LayoutOutput<'_>)
430 -> bool;
431 fn dyn_eq(&self, other: &dyn LayoutPolicyDyn) -> bool;
433 fn dyn_measure_eq(&self, other: &dyn LayoutPolicyDyn) -> bool;
435 fn dyn_placement_eq(&self, other: &dyn LayoutPolicyDyn) -> bool;
437 fn clone_box(&self) -> Box<dyn LayoutPolicyDyn>;
439}
440
441impl<T> LayoutPolicyDyn for T
442where
443 T: LayoutPolicy,
444{
445 fn as_any(&self) -> &dyn Any {
446 self
447 }
448
449 fn measure_dyn(
450 &self,
451 input: &LayoutInput<'_>,
452 output: &mut LayoutOutput<'_>,
453 ) -> Result<ComputedData, MeasurementError> {
454 LayoutPolicy::measure(self, input, output)
455 }
456
457 fn place_children_dyn(
458 &self,
459 input: &PlacementInput<'_>,
460 output: &mut LayoutOutput<'_>,
461 ) -> bool {
462 LayoutPolicy::place_children(self, input, output)
463 }
464
465 fn dyn_eq(&self, other: &dyn LayoutPolicyDyn) -> bool {
466 other
467 .as_any()
468 .downcast_ref::<T>()
469 .is_some_and(|other| self == other)
470 }
471
472 fn dyn_measure_eq(&self, other: &dyn LayoutPolicyDyn) -> bool {
473 other
474 .as_any()
475 .downcast_ref::<T>()
476 .is_some_and(|other| LayoutPolicy::measure_eq(self, other))
477 }
478
479 fn dyn_placement_eq(&self, other: &dyn LayoutPolicyDyn) -> bool {
480 other
481 .as_any()
482 .downcast_ref::<T>()
483 .is_some_and(|other| LayoutPolicy::placement_eq(self, other))
484 }
485
486 fn clone_box(&self) -> Box<dyn LayoutPolicyDyn> {
487 Box::new(self.clone())
488 }
489}
490
491#[doc(hidden)]
493pub trait RenderPolicyDyn: Send + Sync {
494 fn as_any(&self) -> &dyn Any;
496 fn record_dyn(&self, input: &RenderInput<'_>);
498 fn dyn_eq(&self, other: &dyn RenderPolicyDyn) -> bool;
500 fn clone_box(&self) -> Box<dyn RenderPolicyDyn>;
502}
503
504impl<T> RenderPolicyDyn for T
505where
506 T: RenderPolicy,
507{
508 fn as_any(&self) -> &dyn Any {
509 self
510 }
511
512 fn record_dyn(&self, input: &RenderInput<'_>) {
513 RenderPolicy::record(self, input);
514 }
515
516 fn dyn_eq(&self, other: &dyn RenderPolicyDyn) -> bool {
517 other
518 .as_any()
519 .downcast_ref::<T>()
520 .is_some_and(|other| self == other)
521 }
522
523 fn clone_box(&self) -> Box<dyn RenderPolicyDyn> {
524 Box::new(self.clone())
525 }
526}
527
528impl Clone for Box<dyn LayoutPolicyDyn> {
529 fn clone(&self) -> Self {
530 self.clone_box()
531 }
532}
533
534impl Clone for Box<dyn RenderPolicyDyn> {
535 fn clone(&self) -> Self {
536 self.clone_box()
537 }
538}
539
540#[derive(Clone)]
546pub struct LayoutPolicyHandle {
547 policy: Box<dyn LayoutPolicyDyn>,
548}
549
550impl LayoutPolicyHandle {
551 pub(crate) fn into_box(self) -> Box<dyn LayoutPolicyDyn> {
552 self.policy
553 }
554}
555
556impl Default for LayoutPolicyHandle {
557 fn default() -> Self {
558 Self {
559 policy: Box::new(DefaultLayoutPolicy),
560 }
561 }
562}
563
564impl PartialEq for LayoutPolicyHandle {
565 fn eq(&self, other: &Self) -> bool {
566 self.policy.dyn_eq(other.policy.as_ref())
567 }
568}
569
570impl Prop for LayoutPolicyHandle {
571 fn prop_eq(&self, other: &Self) -> bool {
572 self == other
573 }
574}
575
576impl<S> From<S> for LayoutPolicyHandle
577where
578 S: LayoutPolicy,
579{
580 fn from(policy: S) -> Self {
581 Self {
582 policy: Box::new(policy),
583 }
584 }
585}
586
587#[derive(Clone)]
593pub struct RenderPolicyHandle {
594 policy: Box<dyn RenderPolicyDyn>,
595}
596
597impl RenderPolicyHandle {
598 pub(crate) fn into_box(self) -> Box<dyn RenderPolicyDyn> {
599 self.policy
600 }
601}
602
603impl Default for RenderPolicyHandle {
604 fn default() -> Self {
605 Self {
606 policy: Box::new(NoopRenderPolicy),
607 }
608 }
609}
610
611impl PartialEq for RenderPolicyHandle {
612 fn eq(&self, other: &Self) -> bool {
613 self.policy.dyn_eq(other.policy.as_ref())
614 }
615}
616
617impl Prop for RenderPolicyHandle {
618 fn prop_eq(&self, other: &Self) -> bool {
619 self == other
620 }
621}
622
623impl<S> From<S> for RenderPolicyHandle
624where
625 S: RenderPolicy,
626{
627 fn from(policy: S) -> Self {
628 Self {
629 policy: Box::new(policy),
630 }
631 }
632}
633
634#[tessera(crate)]
671pub fn layout_primitive(
672 #[prop(into)] layout_policy: LayoutPolicyHandle,
673 #[prop(into)] render_policy: RenderPolicyHandle,
674 modifier: Modifier,
675 child: Option<RenderSlot>,
676) {
677 modifier.attach();
678 TesseraRuntime::with_mut(|runtime| {
679 runtime.set_current_layout_policy_boxed(layout_policy.into_box());
680 runtime.set_current_render_policy_boxed(render_policy.into_box());
681 });
682 if let Some(child) = child {
683 child.render();
684 }
685}
686
687#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
690pub struct DefaultLayoutPolicy;
691
692impl LayoutPolicy for DefaultLayoutPolicy {
693 fn measure(
694 &self,
695 input: &LayoutInput<'_>,
696 output: &mut LayoutOutput<'_>,
697 ) -> Result<ComputedData, MeasurementError> {
698 if input.children_ids().is_empty() {
699 return Ok(ComputedData::min_from_constraint(
700 input.parent_constraint().as_ref(),
701 ));
702 }
703
704 let nodes_to_measure = input
705 .children_ids()
706 .iter()
707 .map(|&child_id| (child_id, *input.parent_constraint().as_ref()))
708 .collect();
709 let sizes = input.measure_children(nodes_to_measure)?;
710
711 let mut final_width = Px(0);
712 let mut final_height = Px(0);
713 for (child_id, size) in sizes {
714 output.place_child(child_id, PxPosition::ZERO);
715 final_width = final_width.max(size.width);
716 final_height = final_height.max(size.height);
717 }
718
719 Ok(ComputedData {
720 width: final_width,
721 height: final_height,
722 })
723 }
724}
725
726#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
728pub struct NoopRenderPolicy;
729
730impl RenderPolicy for NoopRenderPolicy {}