1use std::{
2 any::TypeId,
3 cell::{Cell, RefCell},
4 collections::HashMap,
5 hash::{Hash, Hasher},
6 rc::Rc,
7};
8
9use cranpose_core::{Node, NodeId};
10use cranpose_foundation::{
11 InvalidationKind, ModifierInvalidation, NodeCapabilities, SemanticsConfiguration,
12};
13use cranpose_ui_layout::{Constraints, MeasurePolicy};
14
15#[cfg(test)]
16use crate::layout::LayoutRuntimeDebugStats;
17use crate::{
18 layout::{LayoutRuntimeState, MeasuredNode},
19 modifier::{
20 Modifier, ModifierChainHandle, ModifierLocalSource, ModifierLocalToken,
21 ModifierLocalsHandle, ModifierNodeSlices, Point, ResolvedModifierLocal, ResolvedModifiers,
22 Size,
23 },
24};
25
26#[derive(Clone, Copy)]
27enum LayoutInvalidationDispatchDiag {
28 Disabled,
29 All,
30 Node(NodeId),
31}
32
33fn layout_invalidation_dispatch_diag() -> LayoutInvalidationDispatchDiag {
34 static MODE: std::sync::OnceLock<LayoutInvalidationDispatchDiag> = std::sync::OnceLock::new();
35 *MODE.get_or_init(|| {
36 let Some(value) = std::env::var_os("CRANPOSE_LAYOUT_INVALIDATION_DISPATCH_DIAG") else {
37 return LayoutInvalidationDispatchDiag::Disabled;
38 };
39 if value == "all" {
40 return LayoutInvalidationDispatchDiag::All;
41 }
42 value.to_string_lossy().parse::<NodeId>().map_or(
43 LayoutInvalidationDispatchDiag::Disabled,
44 LayoutInvalidationDispatchDiag::Node,
45 )
46 })
47}
48
49fn log_layout_invalidation_dispatch(
50 id: NodeId,
51 invalidation: &ModifierInvalidation,
52 curr_caps: NodeCapabilities,
53 prev_caps: NodeCapabilities,
54 modifier: &Modifier,
55) {
56 let enabled = match layout_invalidation_dispatch_diag() {
57 LayoutInvalidationDispatchDiag::Disabled => false,
58 LayoutInvalidationDispatchDiag::All => true,
59 LayoutInvalidationDispatchDiag::Node(target) => target == id,
60 };
61 if enabled {
62 log::warn!(
63 "[layout-invalidation-dispatch] node={id} invalidation={invalidation:?} curr_caps={curr_caps:?} prev_caps={prev_caps:?} modifier={modifier}"
64 );
65 }
66}
67
68#[derive(Clone, Debug)]
73pub struct LayoutState {
74 size: Size,
75 position: Point,
76 is_placed: bool,
77 node_id: Option<NodeId>,
78 pub measurement_constraints: Constraints,
80 pub content_offset: Point,
82}
83
84impl Default for LayoutState {
85 fn default() -> Self {
86 Self {
87 size: Size::default(),
88 position: Point::default(),
89 is_placed: false,
90 node_id: None,
91 measurement_constraints: Constraints {
92 min_width: 0.0,
93 max_width: f32::INFINITY,
94 min_height: 0.0,
95 max_height: f32::INFINITY,
96 },
97 content_offset: Point::default(),
98 }
99 }
100}
101
102impl LayoutState {
103 pub fn size(&self) -> Size {
104 self.size
105 }
106
107 pub fn position(&self) -> Point {
108 self.position
109 }
110
111 pub fn at_origin(mut self) -> Self {
115 self.position = Point::default();
116 self
117 }
118
119 pub fn is_placed(&self) -> bool {
120 self.is_placed
121 }
122
123 pub(crate) fn set_node_id(&mut self, node_id: NodeId) {
124 self.node_id = Some(node_id);
125 }
126
127 pub fn set_size(&mut self, size: Size) {
130 if self.size != size {
131 if let Some(id) = self.node_id {
132 crate::render_state::record_geometry_scene_node(id);
133 }
134 self.size = size;
135 }
136 }
137
138 pub fn place(&mut self, position: Point) {
141 if self.position != position {
142 if let Some(id) = self.node_id {
143 crate::render_state::record_geometry_scene_node(id);
144 }
145 self.position = position;
146 }
147 self.is_placed = true;
148 }
149
150 pub fn clear_placed(&mut self) {
152 self.is_placed = false;
153 }
154}
155
156#[derive(Clone)]
157struct MeasurementCacheEntry {
158 constraints: Constraints,
159 measured: Rc<MeasuredNode>,
160}
161
162#[derive(Clone, Copy, Debug)]
163pub enum IntrinsicKind {
164 MinWidth(f32),
165 MaxWidth(f32),
166 MinHeight(f32),
167 MaxHeight(f32),
168}
169
170impl IntrinsicKind {
171 fn discriminant(&self) -> u8 {
172 match self {
173 IntrinsicKind::MinWidth(_) => 0,
174 IntrinsicKind::MaxWidth(_) => 1,
175 IntrinsicKind::MinHeight(_) => 2,
176 IntrinsicKind::MaxHeight(_) => 3,
177 }
178 }
179
180 fn value_bits(&self) -> u32 {
181 match self {
182 IntrinsicKind::MinWidth(value)
183 | IntrinsicKind::MaxWidth(value)
184 | IntrinsicKind::MinHeight(value)
185 | IntrinsicKind::MaxHeight(value) => value.to_bits(),
186 }
187 }
188}
189
190impl PartialEq for IntrinsicKind {
191 fn eq(&self, other: &Self) -> bool {
192 self.discriminant() == other.discriminant() && self.value_bits() == other.value_bits()
193 }
194}
195
196impl Eq for IntrinsicKind {}
197
198impl Hash for IntrinsicKind {
199 fn hash<H: Hasher>(&self, state: &mut H) {
200 self.discriminant().hash(state);
201 self.value_bits().hash(state);
202 }
203}
204
205#[derive(Default)]
206struct NodeCacheState {
207 epoch: u64,
208 measurements: Vec<MeasurementCacheEntry>,
209 intrinsics: Vec<(IntrinsicKind, f32)>,
210}
211
212#[derive(Clone, Default)]
213pub(crate) struct LayoutNodeCacheHandles {
214 state: Rc<RefCell<NodeCacheState>>,
215}
216
217impl LayoutNodeCacheHandles {
218 pub(crate) fn clear(&self) {
219 let mut state = self.state.borrow_mut();
220 state.measurements.clear();
221 state.intrinsics.clear();
222 state.epoch = 0;
223 }
224
225 pub(crate) fn activate(&self, epoch: u64) {
226 let mut state = self.state.borrow_mut();
227 if state.epoch != epoch {
228 state.measurements.clear();
229 state.intrinsics.clear();
230 state.epoch = epoch;
231 }
232 }
233
234 pub(crate) fn epoch(&self) -> u64 {
235 self.state.borrow().epoch
236 }
237
238 pub(crate) fn get_measurement(&self, constraints: Constraints) -> Option<Rc<MeasuredNode>> {
239 let state = self.state.borrow();
240 state
241 .measurements
242 .iter()
243 .find(|entry| entry.constraints == constraints)
244 .map(|entry| Rc::clone(&entry.measured))
245 }
246
247 pub(crate) fn store_measurement(&self, constraints: Constraints, measured: Rc<MeasuredNode>) {
248 let mut state = self.state.borrow_mut();
249 if let Some(entry) = state
250 .measurements
251 .iter_mut()
252 .find(|entry| entry.constraints == constraints)
253 {
254 entry.measured = measured;
255 } else {
256 state.measurements.push(MeasurementCacheEntry {
257 constraints,
258 measured,
259 });
260 }
261 }
262
263 pub(crate) fn get_intrinsic(&self, kind: &IntrinsicKind) -> Option<f32> {
264 let state = self.state.borrow();
265 state
266 .intrinsics
267 .iter()
268 .find(|(stored_kind, _)| stored_kind == kind)
269 .map(|(_, value)| *value)
270 }
271
272 pub(crate) fn store_intrinsic(&self, kind: IntrinsicKind, value: f32) {
273 let mut state = self.state.borrow_mut();
274 if let Some((_, existing)) = state
275 .intrinsics
276 .iter_mut()
277 .find(|(stored_kind, _)| stored_kind == &kind)
278 {
279 *existing = value;
280 } else {
281 state.intrinsics.push((kind, value));
282 }
283 }
284}
285
286pub struct LayoutNode {
287 pub modifier: Modifier,
288 modifier_chain: ModifierChainHandle,
289 resolved_modifiers: ResolvedModifiers,
290 modifier_capabilities: NodeCapabilities,
291 modifier_child_capabilities: NodeCapabilities,
292 pub measure_policy: Rc<dyn MeasurePolicy>,
293 density: crate::density::Density,
294 pub children: Vec<NodeId>,
296 cache: LayoutNodeCacheHandles,
297 needs_measure: Cell<bool>,
298 needs_layout: Cell<bool>,
299 needs_semantics: Cell<bool>,
300 needs_redraw: Cell<bool>,
301 needs_pointer_pass: Cell<bool>,
302 needs_focus_sync: Cell<bool>,
303 parent: Cell<Option<NodeId>>,
304 folded_parent: Cell<Option<NodeId>>,
305 id: Cell<Option<NodeId>>,
306 owner_context_id: Cell<Option<crate::render_state::AppContextId>>,
307 debug_modifiers: Cell<bool>,
308 is_virtual: bool,
309 virtual_children_count: Cell<usize>,
310
311 modifier_slices_snapshot: RefCell<Rc<ModifierNodeSlices>>,
312 modifier_slices_dirty: Cell<bool>,
313
314 layout_state: Rc<RefCell<LayoutState>>,
315 layout_runtime_state: Rc<RefCell<LayoutRuntimeState>>,
316}
317
318pub(crate) const RECYCLED_LAYOUT_NODE_POOL_LIMIT: usize = 128;
319
320thread_local! {
321 static EMPTY_MEASURE_POLICY: Rc<dyn MeasurePolicy> =
322 Rc::new(crate::layout::policies::EmptyMeasurePolicy);
323}
324
325fn empty_measure_policy() -> Rc<dyn MeasurePolicy> {
326 EMPTY_MEASURE_POLICY.with(Rc::clone)
327}
328
329impl LayoutNode {
330 pub fn new(modifier: Modifier, measure_policy: Rc<dyn MeasurePolicy>) -> Self {
331 Self::new_with_virtual(modifier, measure_policy, false)
332 }
333
334 pub fn new_virtual() -> Self {
337 Self::new_with_virtual(Modifier::empty(), empty_measure_policy(), true)
338 }
339
340 fn new_recycled_shell(is_virtual: bool) -> Self {
341 let mut shell =
342 Self::new_with_virtual(Modifier::empty(), empty_measure_policy(), is_virtual);
343 shell.needs_measure.set(false);
344 shell.needs_layout.set(false);
345 shell.needs_semantics.set(false);
346 shell.needs_redraw.set(false);
347 shell.needs_pointer_pass.set(false);
348 shell.needs_focus_sync.set(false);
349 shell.parent.set(None);
350 shell.folded_parent.set(None);
351 shell.id.set(None);
352 shell.owner_context_id.set(None);
353 shell.debug_modifiers.set(false);
354 shell.virtual_children_count.set(0);
355 shell.cache = LayoutNodeCacheHandles::default();
356 shell.modifier_slices_snapshot = RefCell::new(Rc::default());
357 shell.modifier_slices_dirty = Cell::new(true);
358 shell.layout_state = Rc::new(RefCell::new(LayoutState::default()));
359 shell.layout_runtime_state = Rc::new(RefCell::new(LayoutRuntimeState::default()));
360 shell
361 }
362
363 fn new_with_virtual(
364 modifier: Modifier,
365 measure_policy: Rc<dyn MeasurePolicy>,
366 is_virtual: bool,
367 ) -> Self {
368 let mut node = Self {
369 modifier,
370 modifier_chain: ModifierChainHandle::new(),
371 resolved_modifiers: ResolvedModifiers::default(),
372 modifier_capabilities: NodeCapabilities::default(),
373 modifier_child_capabilities: NodeCapabilities::default(),
374 measure_policy,
375 density: crate::density::Density::default(),
376 children: Vec::new(),
377 cache: LayoutNodeCacheHandles::default(),
378 needs_measure: Cell::new(true),
379 needs_layout: Cell::new(true),
380 needs_semantics: Cell::new(true),
381 needs_redraw: Cell::new(true),
382 needs_pointer_pass: Cell::new(false),
383 needs_focus_sync: Cell::new(false),
384 parent: Cell::new(None),
385 folded_parent: Cell::new(None),
386 id: Cell::new(None),
387 owner_context_id: Cell::new(None),
388 debug_modifiers: Cell::new(false),
389 is_virtual,
390 virtual_children_count: Cell::new(0),
391 modifier_slices_snapshot: RefCell::new(Rc::default()),
392 modifier_slices_dirty: Cell::new(true),
393 layout_state: Rc::new(RefCell::new(LayoutState::default())),
394 layout_runtime_state: Rc::new(RefCell::new(LayoutRuntimeState::default())),
395 };
396 node.sync_modifier_chain();
397 node
398 }
399
400 pub fn set_modifier(&mut self, modifier: Modifier) {
401 let modifier_changed = !self.modifier.structural_eq(&modifier);
402 self.modifier = modifier;
403 self.sync_modifier_chain();
404 if modifier_changed {
405 self.cache.clear();
406 self.request_semantics_update();
407 }
408 }
409
410 fn sync_modifier_chain(&mut self) {
411 let prev_caps = self.modifier_capabilities;
412 let start_parent = self.parent();
413 let mut resolver = move |token: &ModifierLocalToken| {
414 resolve_modifier_local_from_parent_chain(start_parent, token)
415 };
416 self.modifier_chain
417 .set_debug_logging(self.debug_modifiers.get());
418 self.modifier_chain.set_node_id(self.id.get());
419 let modifier_local_invalidations = self
420 .modifier_chain
421 .update_with_resolver(&self.modifier, &mut resolver);
422 self.resolved_modifiers = self.modifier_chain.resolved_modifiers();
423 self.modifier_capabilities = self.modifier_chain.capabilities();
424 self.modifier_child_capabilities = self.modifier_chain.aggregate_child_capabilities();
425
426 self.update_modifier_slices_cache();
427
428 let mut invalidations = self.modifier_chain.take_invalidations();
429 invalidations.extend(modifier_local_invalidations);
430 self.dispatch_modifier_invalidations_with_prev(&invalidations, prev_caps);
431 self.refresh_registry_state();
432 }
433
434 fn update_modifier_slices_cache(&self) {
435 use crate::modifier::collect_modifier_slices_into;
436
437 let mut snapshot = self.modifier_slices_snapshot.borrow_mut();
438 collect_modifier_slices_into(self.modifier_chain.chain(), Rc::make_mut(&mut snapshot));
439 self.modifier_slices_dirty.set(false);
440 }
441
442 pub(crate) fn mark_modifier_slices_dirty(&self) {
443 self.modifier_slices_dirty.set(true);
444 }
445
446 #[cfg(test)]
447 fn dispatch_modifier_invalidations(&self, invalidations: &[ModifierInvalidation]) {
448 self.dispatch_modifier_invalidations_with_prev(invalidations, NodeCapabilities::empty());
449 }
450
451 fn dispatch_modifier_invalidations_with_prev(
452 &self,
453 invalidations: &[ModifierInvalidation],
454 prev_caps: NodeCapabilities,
455 ) {
456 let curr_caps = self.modifier_capabilities;
457 for invalidation in invalidations {
458 self.modifier_slices_dirty.set(true);
459 let has_capability =
460 |capability| curr_caps.contains(capability) || prev_caps.contains(capability);
461 match invalidation.kind() {
462 InvalidationKind::Layout => {
463 if has_capability(NodeCapabilities::LAYOUT) {
464 self.mark_needs_measure();
465 if let Some(id) = self.id.get() {
466 log_layout_invalidation_dispatch(
467 id,
468 invalidation,
469 curr_caps,
470 prev_caps,
471 &self.modifier,
472 );
473 let inside_composition =
474 cranpose_core::composer_context::try_with_composer(|_| ())
475 .is_some();
476 if inside_composition {
477 cranpose_core::bubble_measure_dirty_in_composer(id);
478 } else {
479 crate::schedule_layout_repass(id);
480 }
481 }
482 }
483 }
484 InvalidationKind::Draw => {
485 if has_capability(NodeCapabilities::DRAW)
486 || invalidation.capabilities().contains(NodeCapabilities::DRAW)
487 {
488 self.mark_needs_redraw();
489 }
490 }
491 InvalidationKind::PointerInput => {
492 if has_capability(NodeCapabilities::POINTER_INPUT) {
493 self.mark_needs_pointer_pass();
494 crate::request_pointer_invalidation();
495 if let Some(id) = self.id.get() {
496 crate::schedule_pointer_repass(id);
497 }
498 }
499 }
500 InvalidationKind::Semantics => {
501 self.request_semantics_update();
502 }
503 InvalidationKind::Focus => {
504 if has_capability(NodeCapabilities::FOCUS) {
505 self.mark_needs_focus_sync();
506 crate::request_focus_invalidation();
507 if let Some(id) = self.id.get() {
508 crate::schedule_focus_invalidation(id);
509 }
510 }
511 }
512 }
513 }
514 }
515
516 pub fn density(&self) -> crate::density::Density {
518 self.density
519 }
520
521 pub fn set_density(&mut self, density: crate::density::Density) {
523 if self.density != density {
524 self.density = density;
525 self.cache.clear();
526 self.mark_needs_measure();
527 }
528 }
529
530 pub fn set_measure_policy(&mut self, policy: Rc<dyn MeasurePolicy>) {
531 if !Rc::ptr_eq(&self.measure_policy, &policy) {
532 self.measure_policy = policy;
533 self.cache.clear();
534 self.mark_needs_measure();
535 if let Some(id) = self.id.get() {
536 cranpose_core::bubble_measure_dirty_in_composer(id);
537 }
538 }
539 }
540
541 pub fn mark_needs_measure(&self) {
543 self.needs_measure.set(true);
544 self.needs_layout.set(true);
545 }
546
547 pub fn mark_needs_layout(&self) {
549 self.needs_layout.set(true);
550 }
551
552 pub fn mark_needs_redraw(&self) {
554 self.needs_redraw.set(true);
555 if let Some(id) = self.id.get() {
556 crate::schedule_draw_repass(id);
557 }
558 crate::request_render_invalidation();
559 }
560
561 pub fn needs_measure(&self) -> bool {
563 self.needs_measure.get()
564 }
565
566 pub fn needs_layout(&self) -> bool {
568 self.needs_layout.get()
569 }
570
571 pub fn mark_needs_semantics(&self) {
573 self.needs_semantics.set(true);
574 }
575
576 pub(crate) fn clear_needs_semantics(&self) {
577 self.needs_semantics.set(false);
578 }
579
580 pub fn needs_semantics(&self) -> bool {
582 self.needs_semantics.get()
583 }
584
585 pub fn needs_redraw(&self) -> bool {
587 self.needs_redraw.get()
588 }
589
590 pub fn clear_needs_redraw(&self) {
591 self.needs_redraw.set(false);
592 }
593
594 fn request_semantics_update(&self) {
595 let already_dirty = self.needs_semantics.replace(true);
596 if already_dirty {
597 return;
598 }
599
600 if let Some(id) = self.id.get() {
601 cranpose_core::queue_semantics_invalidation(id);
602 }
603 }
604
605 pub(crate) fn clear_needs_measure(&self) {
606 self.needs_measure.set(false);
607 }
608
609 pub(crate) fn clear_needs_layout(&self) {
610 self.needs_layout.set(false);
611 }
612
613 pub fn mark_needs_pointer_pass(&self) {
615 self.needs_pointer_pass.set(true);
616 }
617
618 pub fn needs_pointer_pass(&self) -> bool {
620 self.needs_pointer_pass.get()
621 }
622
623 pub fn clear_needs_pointer_pass(&self) {
625 self.needs_pointer_pass.set(false);
626 }
627
628 pub fn mark_needs_focus_sync(&self) {
630 self.needs_focus_sync.set(true);
631 }
632
633 pub fn needs_focus_sync(&self) -> bool {
635 self.needs_focus_sync.get()
636 }
637
638 pub fn clear_needs_focus_sync(&self) {
640 self.needs_focus_sync.set(false);
641 }
642
643 pub fn set_node_id(&mut self, id: NodeId) {
645 if let Some(existing) = self.id.replace(Some(id))
646 && let Some(owner_context_id) = self.owner_context_id.take()
647 {
648 unregister_layout_node(owner_context_id, existing);
649 }
650 self.layout_state.borrow_mut().set_node_id(id);
651 let owner_context_id = register_layout_node(id, self);
652 self.owner_context_id.set(Some(owner_context_id));
653 self.refresh_registry_state();
654
655 self.modifier_chain.set_node_id(Some(id));
656 let invalidations = self.modifier_chain.take_invalidations();
657 self.dispatch_modifier_invalidations_with_prev(&invalidations, NodeCapabilities::empty());
658 self.update_modifier_slices_cache();
659 }
660
661 pub fn node_id(&self) -> Option<NodeId> {
663 self.id.get()
664 }
665
666 pub fn set_parent(&self, parent: NodeId) {
669 self.folded_parent.set(Some(parent));
670 self.parent.set(Some(parent));
671 self.refresh_registry_state();
672 }
673
674 pub fn clear_parent(&self) {
676 self.folded_parent.set(None);
677 self.parent.set(None);
678 self.refresh_registry_state();
679 }
680
681 pub fn parent(&self) -> Option<NodeId> {
683 self.parent.get()
684 }
685
686 pub fn folded_parent(&self) -> Option<NodeId> {
688 self.folded_parent.get()
689 }
690
691 pub fn is_virtual(&self) -> bool {
693 self.is_virtual
694 }
695
696 pub(crate) fn cache_handles(&self) -> LayoutNodeCacheHandles {
697 self.cache.clone()
698 }
699
700 pub fn resolved_modifiers(&self) -> ResolvedModifiers {
701 self.resolved_modifiers
702 }
703
704 pub fn modifier_capabilities(&self) -> NodeCapabilities {
705 self.modifier_capabilities
706 }
707
708 pub fn is_window_root(&self) -> bool {
712 self.modifier_capabilities
713 .contains(NodeCapabilities::WINDOW_ROOT)
714 }
715
716 pub fn modifier_child_capabilities(&self) -> NodeCapabilities {
717 self.modifier_child_capabilities
718 }
719
720 pub fn set_debug_modifiers(&mut self, enabled: bool) {
721 self.debug_modifiers.set(enabled);
722 self.modifier_chain.set_debug_logging(enabled);
723 }
724
725 pub fn debug_modifiers_enabled(&self) -> bool {
726 self.debug_modifiers.get()
727 }
728
729 pub fn modifier_locals_handle(&self) -> ModifierLocalsHandle {
730 self.modifier_chain.modifier_locals_handle()
731 }
732
733 pub fn has_layout_modifier_nodes(&self) -> bool {
734 self.modifier_capabilities
735 .contains(NodeCapabilities::LAYOUT)
736 }
737
738 pub fn has_draw_modifier_nodes(&self) -> bool {
739 self.modifier_capabilities.contains(NodeCapabilities::DRAW)
740 }
741
742 pub fn has_pointer_input_modifier_nodes(&self) -> bool {
743 self.modifier_capabilities
744 .contains(NodeCapabilities::POINTER_INPUT)
745 }
746
747 pub fn has_semantics_modifier_nodes(&self) -> bool {
748 self.modifier_capabilities
749 .contains(NodeCapabilities::SEMANTICS)
750 }
751
752 pub fn has_focus_modifier_nodes(&self) -> bool {
753 self.modifier_capabilities.contains(NodeCapabilities::FOCUS)
754 }
755
756 fn refresh_registry_state(&self) {
757 if let (Some(id), Some(owner_context_id)) = (self.id.get(), self.owner_context_id.get()) {
758 let parent = self.parent();
759 let capabilities = self.modifier_child_capabilities();
760 let modifier_locals = self.modifier_locals_handle();
761 let _ = crate::render_state::with_layout_node_registry_by_app_context(
762 owner_context_id,
763 |registry| {
764 registry.update_entry(id, parent, capabilities, modifier_locals);
765 },
766 );
767 }
768 }
769
770 pub fn modifier_slices_snapshot(&self) -> Rc<ModifierNodeSlices> {
771 if self.modifier_slices_dirty.get() {
772 self.update_modifier_slices_cache();
773 }
774 self.modifier_slices_snapshot.borrow().clone()
775 }
776
777 pub fn layout_state(&self) -> LayoutState {
779 self.layout_state.borrow().clone()
780 }
781
782 pub fn measured_size(&self) -> Size {
784 self.layout_state.borrow().size
785 }
786
787 pub fn position(&self) -> Point {
789 self.layout_state.borrow().position
790 }
791
792 pub fn is_placed(&self) -> bool {
794 self.layout_state.borrow().is_placed
795 }
796
797 pub fn set_measured_size(&self, size: Size) {
801 self.layout_state.borrow_mut().set_size(size);
802 }
803
804 pub fn set_position(&self, position: Point) {
807 self.layout_state.borrow_mut().place(position);
808 }
809
810 pub fn set_measurement_constraints(&self, constraints: Constraints) {
812 self.layout_state.borrow_mut().measurement_constraints = constraints;
813 }
814
815 pub fn set_content_offset(&self, offset: Point) {
817 self.layout_state.borrow_mut().content_offset = offset;
818 }
819
820 pub fn clear_placed(&self) {
822 self.layout_state.borrow_mut().is_placed = false;
823 }
824
825 pub fn semantics_configuration(&self) -> Option<SemanticsConfiguration> {
826 crate::modifier::collect_semantics_from_chain(self.modifier_chain.chain())
827 }
828
829 pub(crate) fn modifier_chain(&self) -> &ModifierChainHandle {
830 &self.modifier_chain
831 }
832
833 pub fn with_text_field_modifier_mut<R>(
838 &mut self,
839 f: impl FnMut(&mut crate::TextFieldModifierNode) -> R,
840 ) -> Option<R> {
841 self.modifier_chain.with_text_field_modifier_mut(f)
842 }
843
844 pub fn layout_state_handle(&self) -> Rc<RefCell<LayoutState>> {
847 self.layout_state.clone()
848 }
849
850 pub(crate) fn layout_runtime_state_handle(&self) -> Rc<RefCell<LayoutRuntimeState>> {
851 self.layout_runtime_state.clone()
852 }
853
854 #[cfg(test)]
855 pub(crate) fn layout_runtime_debug_stats(&self) -> LayoutRuntimeDebugStats {
856 self.layout_runtime_state.borrow().debug_stats()
857 }
858}
859impl Clone for LayoutNode {
860 fn clone(&self) -> Self {
861 let mut node = Self {
862 modifier: self.modifier.clone(),
863 modifier_chain: ModifierChainHandle::new(),
864 resolved_modifiers: ResolvedModifiers::default(),
865 modifier_capabilities: self.modifier_capabilities,
866 modifier_child_capabilities: self.modifier_child_capabilities,
867 measure_policy: self.measure_policy.clone(),
868 density: self.density,
869 children: self.children.clone(),
870 cache: self.cache.clone(),
871 needs_measure: Cell::new(self.needs_measure.get()),
872 needs_layout: Cell::new(self.needs_layout.get()),
873 needs_semantics: Cell::new(self.needs_semantics.get()),
874 needs_redraw: Cell::new(self.needs_redraw.get()),
875 needs_pointer_pass: Cell::new(self.needs_pointer_pass.get()),
876 needs_focus_sync: Cell::new(self.needs_focus_sync.get()),
877 parent: Cell::new(self.parent.get()),
878 folded_parent: Cell::new(self.folded_parent.get()),
879 id: Cell::new(None),
880 owner_context_id: Cell::new(None),
881 debug_modifiers: Cell::new(self.debug_modifiers.get()),
882 is_virtual: self.is_virtual,
883 virtual_children_count: Cell::new(self.virtual_children_count.get()),
884 modifier_slices_snapshot: RefCell::new(Rc::default()),
885 modifier_slices_dirty: Cell::new(true),
886 layout_state: self.layout_state.clone(),
887 layout_runtime_state: self.layout_runtime_state.clone(),
888 };
889 node.sync_modifier_chain();
890 node
891 }
892}
893
894impl Node for LayoutNode {
895 fn mount(&mut self) {
896 let (chain, mut context) = self.modifier_chain.chain_and_context_mut();
897 chain.repair_chain();
898 chain.attach_nodes(&mut *context);
899 }
900
901 fn unmount(&mut self) {
902 self.modifier_chain.chain_mut().detach_nodes();
903 }
904
905 fn set_node_id(&mut self, id: NodeId) {
906 LayoutNode::set_node_id(self, id);
907 }
908
909 fn insert_child(&mut self, child: NodeId) -> bool {
910 if self.children.contains(&child) {
911 return false;
912 }
913 if is_virtual_node(child) {
914 let count = self.virtual_children_count.get();
915 self.virtual_children_count.set(count + 1);
916 }
917 self.children.push(child);
918 self.cache.clear();
919 self.mark_needs_measure();
920 true
921 }
922
923 fn remove_child(&mut self, child: NodeId) -> bool {
924 let before = self.children.len();
925 self.children.retain(|&id| id != child);
926 let removed = self.children.len() < before;
927 if removed {
928 if is_virtual_node(child) {
929 let count = self.virtual_children_count.get();
930 if count > 0 {
931 self.virtual_children_count.set(count - 1);
932 }
933 }
934 self.cache.clear();
935 self.mark_needs_measure();
936 }
937 removed
938 }
939
940 fn move_child(&mut self, from: usize, to: usize) {
941 if from == to || from >= self.children.len() {
942 return;
943 }
944 let child = self.children.remove(from);
945 let target = to.min(self.children.len());
946 self.children.insert(target, child);
947 self.cache.clear();
948 self.mark_needs_measure();
949 }
950
951 fn update_children(&mut self, children: &[NodeId]) {
952 self.children.clear();
953 self.children.extend_from_slice(children);
954 self.cache.clear();
955 self.mark_needs_measure();
956 }
957
958 fn children(&self) -> Vec<NodeId> {
959 self.children.clone()
960 }
961
962 fn collect_children_into(&self, out: &mut smallvec::SmallVec<[NodeId; 8]>) {
963 out.clear();
964 out.extend(self.children.iter().copied());
965 }
966
967 fn on_attached_to_parent(&mut self, parent: NodeId) {
968 self.set_parent(parent);
969 }
970
971 fn on_removed_from_parent(&mut self) {
972 self.clear_parent();
973 }
974
975 fn parent(&self) -> Option<NodeId> {
976 self.parent.get()
977 }
978
979 fn mark_needs_layout(&self) {
980 self.needs_layout.set(true);
981 }
982
983 fn needs_layout(&self) -> bool {
984 self.needs_layout.get()
985 }
986
987 fn mark_needs_measure(&self) {
988 self.needs_measure.set(true);
989 self.needs_layout.set(true);
990 }
991
992 fn needs_measure(&self) -> bool {
993 self.needs_measure.get()
994 }
995
996 fn mark_needs_semantics(&self) {
997 self.needs_semantics.set(true);
998 }
999
1000 fn needs_semantics(&self) -> bool {
1001 self.needs_semantics.get()
1002 }
1003
1004 fn set_parent_for_bubbling(&mut self, parent: NodeId) {
1005 if self.parent.get().is_none() {
1006 self.parent.set(Some(parent));
1007 }
1008 }
1009
1010 fn recycle_key(&self) -> Option<TypeId> {
1011 Some(TypeId::of::<Self>())
1012 }
1013
1014 fn recycle_pool_limit(&self) -> Option<usize> {
1015 Some(RECYCLED_LAYOUT_NODE_POOL_LIMIT)
1016 }
1017
1018 fn prepare_for_recycle(&mut self) {
1019 *self = Self::new_recycled_shell(self.is_virtual);
1020 }
1021
1022 fn rehouse_for_recycle(&self) -> Option<Box<dyn cranpose_core::Node>> {
1023 Some(Box::new(Self::new_recycled_shell(self.is_virtual)))
1024 }
1025
1026 fn rehouse_for_live_compaction(&mut self) -> Option<Box<dyn cranpose_core::Node>> {
1027 let mut previous = std::mem::replace(self, Self::new_recycled_shell(self.is_virtual));
1028 let node_id = previous.id.replace(None);
1029 let parent = previous.parent.get();
1030 let folded_parent = previous.folded_parent.get();
1031 let debug_modifiers = previous.debug_modifiers.get();
1032 let needs_measure = previous.needs_measure.get();
1033 let needs_layout = previous.needs_layout.get();
1034 let needs_semantics = previous.needs_semantics.get();
1035 let needs_redraw = previous.needs_redraw.get();
1036 let needs_pointer_pass = previous.needs_pointer_pass.get();
1037 let needs_focus_sync = previous.needs_focus_sync.get();
1038 let virtual_children_count = previous.virtual_children_count.get();
1039 let children = previous.children.to_vec();
1040 let modifier = previous.modifier.rehouse_for_live_compaction();
1041 let measure_policy = previous.measure_policy.clone();
1042 let layout_state = previous.layout_state.clone();
1043 let layout_runtime_state = previous.layout_runtime_state.clone();
1044
1045 previous.modifier_chain.chain_mut().detach_nodes();
1046
1047 let mut compact = Self::new_with_virtual(modifier, measure_policy, previous.is_virtual);
1048 compact.children = children;
1049 compact.parent.set(parent);
1050 compact.folded_parent.set(folded_parent);
1051 compact.id.set(node_id);
1052 compact.debug_modifiers.set(debug_modifiers);
1053 compact.needs_measure.set(needs_measure);
1054 compact.needs_layout.set(needs_layout);
1055 compact.needs_semantics.set(needs_semantics);
1056 compact.needs_redraw.set(needs_redraw);
1057 compact.needs_pointer_pass.set(needs_pointer_pass);
1058 compact.needs_focus_sync.set(needs_focus_sync);
1059 compact.virtual_children_count.set(virtual_children_count);
1060 compact.layout_state = layout_state;
1061 compact.layout_runtime_state = layout_runtime_state;
1062 compact.sync_modifier_chain();
1063 if let Some(id) = node_id {
1064 let owner_context_id = register_layout_node(id, &compact);
1065 compact.owner_context_id.set(Some(owner_context_id));
1066 }
1067
1068 Some(Box::new(compact))
1069 }
1070}
1071
1072impl Drop for LayoutNode {
1073 fn drop(&mut self) {
1074 if let (Some(id), Some(owner_context_id)) = (self.id.get(), self.owner_context_id.get()) {
1075 unregister_layout_node(owner_context_id, id);
1076 }
1077 }
1078}
1079
1080const MIN_RETAINED_LAYOUT_NODE_REGISTRY_CAPACITY: usize = 128;
1081const VIRTUAL_NODE_ID_START: NodeId = 0xC0000000;
1082
1083#[cfg(test)]
1084#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
1085struct LayoutNodeRegistryDebugStats {
1086 len: usize,
1087 capacity: usize,
1088}
1089
1090struct LayoutNodeRegistryEntry {
1091 parent: Option<NodeId>,
1092 modifier_child_capabilities: NodeCapabilities,
1093 modifier_locals: ModifierLocalsHandle,
1094 is_virtual: bool,
1095}
1096
1097pub(crate) struct LayoutNodeRegistryState {
1098 entries: RefCell<HashMap<NodeId, LayoutNodeRegistryEntry>>,
1099 virtual_node_id_counter: Cell<NodeId>,
1100}
1101
1102impl LayoutNodeRegistryState {
1103 pub(crate) fn new() -> Self {
1104 Self {
1105 entries: RefCell::new(HashMap::new()),
1106 virtual_node_id_counter: Cell::new(VIRTUAL_NODE_ID_START),
1107 }
1108 }
1109
1110 fn register(&self, id: NodeId, node: &LayoutNode) {
1111 self.entries.borrow_mut().insert(
1112 id,
1113 LayoutNodeRegistryEntry {
1114 parent: node.parent(),
1115 modifier_child_capabilities: node.modifier_child_capabilities(),
1116 modifier_locals: node.modifier_locals_handle(),
1117 is_virtual: node.is_virtual(),
1118 },
1119 );
1120 }
1121
1122 fn unregister(&self, id: NodeId) {
1123 let mut entries = self.entries.borrow_mut();
1124 entries.remove(&id);
1125 let should_shrink = (entries.len() <= MIN_RETAINED_LAYOUT_NODE_REGISTRY_CAPACITY
1126 && entries.capacity() > MIN_RETAINED_LAYOUT_NODE_REGISTRY_CAPACITY)
1127 || entries.capacity()
1128 > entries
1129 .len()
1130 .max(MIN_RETAINED_LAYOUT_NODE_REGISTRY_CAPACITY)
1131 .saturating_mul(4);
1132 if should_shrink {
1133 let retained = entries
1134 .len()
1135 .max(MIN_RETAINED_LAYOUT_NODE_REGISTRY_CAPACITY);
1136 let mut rebuilt = HashMap::new();
1137 rebuilt.reserve(retained);
1138 rebuilt.extend(entries.drain());
1139 *entries = rebuilt;
1140 }
1141 }
1142
1143 fn update_entry(
1144 &self,
1145 id: NodeId,
1146 parent: Option<NodeId>,
1147 modifier_child_capabilities: NodeCapabilities,
1148 modifier_locals: ModifierLocalsHandle,
1149 ) {
1150 if let Some(entry) = self.entries.borrow_mut().get_mut(&id) {
1151 entry.parent = parent;
1152 entry.modifier_child_capabilities = modifier_child_capabilities;
1153 entry.modifier_locals = modifier_locals;
1154 }
1155 }
1156
1157 #[cfg(test)]
1158 fn stats(&self) -> LayoutNodeRegistryDebugStats {
1159 let entries = self.entries.borrow();
1160 LayoutNodeRegistryDebugStats {
1161 len: entries.len(),
1162 capacity: entries.capacity(),
1163 }
1164 }
1165
1166 fn is_virtual_node(&self, id: NodeId) -> bool {
1167 self.entries
1168 .borrow()
1169 .get(&id)
1170 .is_some_and(|entry| entry.is_virtual)
1171 }
1172
1173 fn allocate_virtual_node_id(&self) -> NodeId {
1174 let id = self.virtual_node_id_counter.get();
1175 self.virtual_node_id_counter.set(id.wrapping_add(1));
1176 id
1177 }
1178
1179 fn resolve_modifier_local_from_parent_chain(
1180 &self,
1181 start: Option<NodeId>,
1182 token: &ModifierLocalToken,
1183 ) -> Option<ResolvedModifierLocal> {
1184 let mut current = start;
1185 while let Some(parent_id) = current {
1186 let (next_parent, resolved) = {
1187 let entries = self.entries.borrow();
1188 if let Some(entry) = entries.get(&parent_id) {
1189 let resolved = if entry
1190 .modifier_child_capabilities
1191 .contains(NodeCapabilities::MODIFIER_LOCALS)
1192 {
1193 entry
1194 .modifier_locals
1195 .borrow()
1196 .resolve(token)
1197 .map(|value| value.with_source(ModifierLocalSource::Ancestor))
1198 } else {
1199 None
1200 };
1201 (entry.parent, resolved)
1202 } else {
1203 (None, None)
1204 }
1205 };
1206 if let Some(value) = resolved {
1207 return Some(value);
1208 }
1209 current = next_parent;
1210 }
1211 None
1212 }
1213}
1214
1215pub(crate) fn register_layout_node(
1216 id: NodeId,
1217 node: &LayoutNode,
1218) -> crate::render_state::AppContextId {
1219 let owner_context_id = crate::render_state::current_app_context_id();
1220 let _ = crate::render_state::with_layout_node_registry_by_app_context(
1221 owner_context_id,
1222 |registry| {
1223 registry.register(id, node);
1224 },
1225 );
1226 owner_context_id
1227}
1228
1229pub(crate) fn unregister_layout_node(
1230 owner_context_id: crate::render_state::AppContextId,
1231 id: NodeId,
1232) {
1233 let _ = crate::render_state::with_layout_node_registry_by_app_context(
1234 owner_context_id,
1235 |registry| {
1236 registry.unregister(id);
1237 },
1238 );
1239}
1240
1241#[cfg(test)]
1242fn layout_node_registry_stats() -> LayoutNodeRegistryDebugStats {
1243 crate::render_state::with_layout_node_registry(LayoutNodeRegistryState::stats)
1244}
1245
1246pub(crate) fn is_virtual_node(id: NodeId) -> bool {
1247 crate::render_state::with_layout_node_registry(|registry| registry.is_virtual_node(id))
1248}
1249
1250pub(crate) fn allocate_virtual_node_id() -> NodeId {
1251 crate::render_state::with_layout_node_registry(
1252 LayoutNodeRegistryState::allocate_virtual_node_id,
1253 )
1254}
1255
1256fn resolve_modifier_local_from_parent_chain(
1257 start: Option<NodeId>,
1258 token: &ModifierLocalToken,
1259) -> Option<ResolvedModifierLocal> {
1260 crate::render_state::with_layout_node_registry(|registry| {
1261 registry.resolve_modifier_local_from_parent_chain(start, token)
1262 })
1263}
1264
1265#[cfg(test)]
1266#[path = "tests/layout_node_tests.rs"]
1267mod tests;