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