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