1use std::{
2 any::TypeId,
3 cell::{Cell, RefCell},
4 rc::Rc,
5};
6
7use cranpose_core::{Node, NodeId, NodeIdCell};
8use cranpose_foundation::{
9 InvalidationKind, ModifierInvalidation, ModifierInvalidations, NodeCapabilities,
10 SemanticsConfiguration,
11};
12use cranpose_ui_layout::MeasurePolicy;
13
14use super::layout_invalidation_diag::log_layout_invalidation_dispatch;
15#[cfg(test)]
16use crate::layout::LayoutRuntimeDebugStats;
17use crate::{
18 layout::LayoutRuntimeState,
19 modifier::{
20 InPlaceUpdate, Modifier, ModifierChainHandle, ModifierLocalToken, ModifierLocalsHandle,
21 ModifierNodeSlices, Point, ResolvedModifiers, Size,
22 },
23 render_state::AppContext,
24 widgets::nodes::{
25 ChildPlacement, LayoutDirt, LayoutParts, LayoutState, NodeCache,
26 layout_node_registry::{
27 register_layout_node, resolve_modifier_local_from_parent_chain, unregister_layout_node,
28 },
29 },
30};
31
32#[repr(C)]
39pub struct LayoutNode {
40 parts: Rc<LayoutParts>,
41 pub(crate) children: Vec<NodeId>,
43
44 pub(crate) measure_policy: Rc<dyn MeasurePolicy>,
47 density: crate::density::Density,
50 is_virtual: bool,
51 needs_semantics: Cell<bool>,
52 descendant_needs_semantics: Cell<bool>,
56 needs_redraw: Cell<bool>,
57 needs_pointer_pass: Cell<bool>,
58 needs_focus_sync: Cell<bool>,
59 modifier_slices_dirty: Cell<bool>,
60 debug_modifiers: Cell<bool>,
61
62 id: NodeIdCell,
63 parent: NodeIdCell,
64 folded_parent: NodeIdCell,
65 modifier_slices_snapshot: crate::modifier::SlicesSnapshot,
66
67 semantics_reach: Cell<Option<cranpose_foundation::SemanticsReach>>,
71 owner_context_id: Cell<Option<crate::render_state::AppContextId>>,
72 modifier_chain: ModifierChainHandle,
73 pub(crate) modifier: Modifier,
76 #[cfg(feature = "inspection")]
78 pub source_trace: Rc<[cranpose_core::source_trace::SourceLocation]>,
79}
80
81pub(crate) fn empty_measure_policy() -> Rc<dyn MeasurePolicy> {
82 crate::thread_state::with(|state| {
83 Rc::clone(
84 state
85 .empty_measure_policy
86 .get_or_init(|| Rc::new(crate::layout::policies::EmptyMeasurePolicy)),
87 )
88 })
89}
90
91impl LayoutNode {
92 pub fn new(modifier: Modifier, measure_policy: Rc<dyn MeasurePolicy>) -> Self {
94 Self::new_with_virtual(modifier, measure_policy, false)
95 }
96
97 pub fn new_virtual() -> Self {
100 Self::new_with_virtual(Modifier::empty(), empty_measure_policy(), true)
101 }
102
103 fn new_recycled_shell(is_virtual: bool) -> Self {
104 let mut shell =
105 Self::new_with_virtual(Modifier::empty(), empty_measure_policy(), is_virtual);
106 shell.parts.cache().set_dirt(LayoutDirt::CLEAN);
107 shell.needs_semantics.set(false);
108 shell.descendant_needs_semantics.set(false);
109 shell.needs_redraw.set(false);
110 shell.needs_pointer_pass.set(false);
111 shell.needs_focus_sync.set(false);
112 shell.parent.set(None);
113 shell.folded_parent.set(None);
114 shell.id.set(None);
115 shell.owner_context_id.set(None);
116 shell.debug_modifiers.set(false);
117 shell.modifier_slices_dirty = Cell::new(true);
118 shell
119 }
120
121 fn new_with_virtual(
122 modifier: Modifier,
123 measure_policy: Rc<dyn MeasurePolicy>,
124 is_virtual: bool,
125 ) -> Self {
126 let parts = Rc::new(LayoutParts::new(LayoutRuntimeState::new(Rc::clone(
127 &measure_policy,
128 ))));
129 let mut node = Self {
130 #[cfg(feature = "inspection")]
131 source_trace: cranpose_core::source_trace::current_source_trace(),
132 modifier,
133 modifier_chain: ModifierChainHandle::detached(),
134 measure_policy,
135 density: crate::density::Density::default(),
136 children: Vec::new(),
137 needs_semantics: Cell::new(true),
138 descendant_needs_semantics: Cell::new(false),
139 semantics_reach: Cell::new(None),
140 needs_redraw: Cell::new(true),
141 needs_pointer_pass: Cell::new(false),
142 needs_focus_sync: Cell::new(false),
143 parent: NodeIdCell::new(None),
144 folded_parent: NodeIdCell::new(None),
145 id: NodeIdCell::new(None),
146 owner_context_id: Cell::new(None),
147 debug_modifiers: Cell::new(false),
148 is_virtual,
149 modifier_slices_snapshot: crate::modifier::SlicesSnapshot::default(),
150 modifier_slices_dirty: Cell::new(true),
151 parts,
152 };
153 node.sync_modifier_chain(None);
154 node
155 }
156
157 pub fn children(&self) -> &[NodeId] {
159 &self.children
160 }
161
162 pub fn modifier(&self) -> Modifier {
164 self.modifier.clone()
165 }
166
167 pub fn set_modifier(&mut self, modifier: Modifier) {
170 #[cfg(feature = "inspection")]
171 {
172 let trace = cranpose_core::source_trace::current_source_trace();
173 if !trace.is_empty() {
174 self.source_trace = trace;
175 }
176 }
177 if self.modifier == modifier
181 && !self
182 .modifier_capabilities()
183 .contains(NodeCapabilities::MODIFIER_LOCALS)
184 {
185 return;
186 }
187 let update = self.modifier.in_place_update(&modifier);
190 let modifier_changed = update.is_some() || !self.modifier.structural_eq(&modifier);
191 self.modifier = modifier;
192 self.sync_modifier_chain(update);
193 if modifier_changed {
194 self.parts.cache().clear();
195 self.request_semantics_update();
196 }
197 }
198
199 fn sync_modifier_chain(&mut self, in_place: Option<InPlaceUpdate>) {
203 let prev_caps = self.modifier_capabilities();
204 let start_parent = self.parent();
205 let mut resolver = move |token: &ModifierLocalToken| {
206 resolve_modifier_local_from_parent_chain(start_parent, token)
207 };
208 self.modifier_chain
209 .set_debug_logging(self.debug_modifiers.get());
210 let mut context = self.modifier_chain.context(self.id.get());
211 let in_place = in_place.is_some_and(|update| {
212 self.modifier_chain
213 .update_elements_in_place(&self.modifier, update, &mut context)
214 });
215 let modifier_local_invalidations = if in_place {
216 ModifierInvalidations::new()
217 } else {
218 self.modifier_chain
219 .update_with_resolver(&self.modifier, &mut resolver, &mut context)
220 };
221 if prev_caps.contains(NodeCapabilities::WINDOW_ROOT)
222 != self
223 .modifier_capabilities()
224 .contains(NodeCapabilities::WINDOW_ROOT)
225 {
226 self.note_semantics_layout_change();
227 }
228 if !in_place {
232 self.forget_semantics_reach();
233 }
234 let keep_slices = in_place && !self.modifier_slices_dirty.get();
235 if !keep_slices {
236 self.modifier_slices_dirty.set(true);
237 }
238
239 let mut invalidations = context.take_invalidations();
240 invalidations.extend(modifier_local_invalidations);
241 self.dispatch_modifier_invalidations_with_prev(&invalidations, prev_caps, keep_slices);
242 if !in_place {
245 self.refresh_registry_state();
246 }
247 }
248
249 fn update_modifier_slices_cache(&self) {
250 self.modifier_slices_snapshot.collect(
251 self.modifier_chain.chain(),
252 Some(&self.parts),
253 self.density.density(),
254 );
255 self.modifier_slices_dirty.set(false);
256 }
257
258 #[cfg(test)]
260 pub(crate) fn modifier_slices_ready(&self) -> bool {
261 !self.modifier_slices_dirty.get()
262 }
263
264 pub(crate) fn mark_modifier_slices_dirty(&self) {
265 self.modifier_slices_dirty.set(true);
266 }
267
268 #[cfg(test)]
269 fn dispatch_modifier_invalidations(&self, invalidations: &[ModifierInvalidation]) {
270 self.dispatch_modifier_invalidations_with_prev(
271 invalidations,
272 NodeCapabilities::empty(),
273 false,
274 );
275 }
276
277 fn dispatch_modifier_invalidations_with_prev(
280 &self,
281 invalidations: &[ModifierInvalidation],
282 prev_caps: NodeCapabilities,
283 keep_slices: bool,
284 ) {
285 let curr_caps = self.modifier_capabilities();
286 for invalidation in invalidations {
287 if !keep_slices {
288 self.modifier_slices_dirty.set(true);
289 }
290 let has_capability =
291 |capability| curr_caps.contains(capability) || prev_caps.contains(capability);
292 match invalidation.kind() {
293 InvalidationKind::Layout => {
294 if has_capability(NodeCapabilities::LAYOUT) {
295 self.mark_needs_measure();
296 if let Some(id) = self.id.get() {
297 log_layout_invalidation_dispatch(
298 id,
299 invalidation,
300 curr_caps,
301 prev_caps,
302 &self.modifier,
303 );
304 let inside_composition =
305 cranpose_core::composer_context::try_with_composer(|_| ())
306 .is_some();
307 if inside_composition {
308 cranpose_core::bubble_measure_dirty_in_composer(id);
309 } else {
310 crate::schedule_layout_repass(id);
311 }
312 }
313 }
314 }
315 InvalidationKind::Draw => {
316 if has_capability(NodeCapabilities::DRAW)
317 || invalidation.capabilities().contains(NodeCapabilities::DRAW)
318 {
319 self.mark_needs_redraw();
320 }
321 }
322 InvalidationKind::PointerInput => {
323 if has_capability(NodeCapabilities::POINTER_INPUT) {
324 self.mark_needs_pointer_pass();
325 crate::request_pointer_invalidation();
326 if let Some(id) = self.id.get() {
327 crate::schedule_pointer_repass(id);
328 }
329 }
330 }
331 InvalidationKind::Semantics => {
332 self.request_semantics_update();
333 }
334 InvalidationKind::Focus => {
335 if has_capability(NodeCapabilities::FOCUS) {
336 self.mark_needs_focus_sync();
337 crate::request_focus_invalidation();
338 if let Some(id) = self.id.get() {
339 crate::schedule_focus_invalidation(id);
340 }
341 }
342 }
343 }
344 }
345 }
346
347 pub fn density(&self) -> crate::density::Density {
349 self.density
350 }
351
352 pub fn set_density(&mut self, density: crate::density::Density) {
354 if self.density != density {
355 self.density = density;
356 self.parts.cache().clear();
357 self.modifier_slices_dirty.set(true);
358 self.mark_needs_measure();
359 }
360 }
361
362 pub fn set_layout_direction(&mut self, direction: crate::LayoutDirection) {
364 if self.modifier_chain.set_layout_direction(direction) {
365 self.parts.cache().clear();
366 self.modifier_slices_dirty.set(true);
367 self.mark_needs_measure();
368 }
369 }
370
371 pub fn set_measure_policy(&mut self, policy: Rc<dyn MeasurePolicy>) {
374 if !Rc::ptr_eq(&self.measure_policy, &policy) {
375 self.measure_policy = policy;
376 self.parts.cache().clear();
377 self.mark_needs_measure();
378 if let Some(id) = self.id.get() {
379 cranpose_core::bubble_measure_dirty_in_composer(id);
380 }
381 }
382 }
383
384 pub fn mark_needs_measure(&self) {
386 self.parts.cache().mark_needs_measure();
387 }
388
389 pub fn mark_needs_layout(&self) {
391 self.parts.cache().mark_needs_layout();
392 }
393
394 pub fn mark_needs_redraw(&self) {
396 self.needs_redraw.set(true);
397 if let Some(id) = self.id.get() {
398 crate::schedule_draw_repass(id);
399 }
400 crate::request_render_invalidation();
401 }
402
403 pub fn needs_measure(&self) -> bool {
405 self.parts.cache().dirt().measure
406 }
407
408 pub fn needs_layout(&self) -> bool {
410 self.parts.cache().dirt().layout
411 }
412
413 pub fn mark_needs_semantics(&self) {
415 self.needs_semantics.set(true);
416 self.forget_semantics_reach();
417 }
418
419 pub(crate) fn clear_needs_semantics(&self) {
420 self.needs_semantics.set(false);
421 self.descendant_needs_semantics.set(false);
422 }
423
424 pub fn needs_semantics(&self) -> bool {
427 self.needs_semantics.get() || self.descendant_needs_semantics.get()
428 }
429
430 pub(crate) fn semantics_changed(&self) -> bool {
433 self.needs_semantics.get()
434 }
435
436 pub fn needs_redraw(&self) -> bool {
438 self.needs_redraw.get()
439 }
440
441 pub fn clear_needs_redraw(&self) {
443 self.needs_redraw.set(false);
444 }
445
446 fn request_semantics_update(&self) {
447 let already_dirty = self.needs_semantics.replace(true);
448 if already_dirty {
449 return;
450 }
451
452 if let Some(id) = self.id.get() {
453 cranpose_core::queue_semantics_invalidation(id);
454 }
455 }
456
457 pub(crate) fn clear_needs_measure(&self) {
458 self.parts.cache().clear_needs_measure();
459 }
460
461 pub(crate) fn clear_needs_layout(&self) {
464 self.parts.cache().clear_layout_dirt();
465 }
466
467 pub fn mark_needs_pointer_pass(&self) {
469 self.needs_pointer_pass.set(true);
470 }
471
472 pub fn needs_pointer_pass(&self) -> bool {
474 self.needs_pointer_pass.get()
475 }
476
477 pub fn clear_needs_pointer_pass(&self) {
479 self.needs_pointer_pass.set(false);
480 }
481
482 pub fn mark_needs_focus_sync(&self) {
484 self.needs_focus_sync.set(true);
485 }
486
487 pub fn needs_focus_sync(&self) -> bool {
489 self.needs_focus_sync.get()
490 }
491
492 pub fn clear_needs_focus_sync(&self) {
494 self.needs_focus_sync.set(false);
495 }
496
497 pub fn set_node_id(&mut self, id: NodeId) {
499 if self.needs_redraw.get() {
502 crate::render_state::note_retained_redraw(id);
503 }
504 let previous = self.id.replace(Some(id));
505 if let Some(existing) = previous
506 && let Some(owner_context_id) = self.owner_context_id.take()
507 {
508 unregister_layout_node(owner_context_id, existing);
509 }
510 self.parts.layout_state().borrow_mut().set_node_id(id);
511 let owner_context_id = register_layout_node(id, self);
514 self.owner_context_id.set(Some(owner_context_id));
515
516 let mut context = self.modifier_chain.context(Some(id));
517 self.modifier_chain.move_to_node(previous, &mut context);
518 let invalidations = context.take_invalidations();
519 self.dispatch_modifier_invalidations_with_prev(
520 &invalidations,
521 NodeCapabilities::empty(),
522 false,
523 );
524 self.modifier_slices_dirty.set(true);
526 }
527
528 pub fn node_id(&self) -> Option<NodeId> {
530 self.id.get()
531 }
532
533 pub fn set_parent(&self, parent: NodeId) {
536 if self.parent.get() == Some(parent) && self.folded_parent.get() == Some(parent) {
539 return;
540 }
541 self.folded_parent.set(Some(parent));
542 self.parent.set(Some(parent));
543 self.refresh_registry_state();
544 }
545
546 pub fn clear_parent(&self) {
548 self.folded_parent.set(None);
549 self.parent.set(None);
550 self.refresh_registry_state();
551 }
552
553 pub fn parent(&self) -> Option<NodeId> {
555 self.parent.get()
556 }
557
558 pub fn folded_parent(&self) -> Option<NodeId> {
560 self.folded_parent.get()
561 }
562
563 pub(crate) fn cache(&self) -> &NodeCache {
564 self.parts.cache()
565 }
566
567 pub fn resolved_modifiers(&self) -> ResolvedModifiers {
569 self.modifier_chain.resolved_modifiers()
570 }
571
572 pub(crate) fn parent_data(&self) -> cranpose_ui_layout::ParentData {
574 self.modifier_chain.parent_data()
575 }
576
577 pub fn modifier_capabilities(&self) -> NodeCapabilities {
579 self.modifier_chain.capabilities()
580 }
581
582 pub fn is_window_root(&self) -> bool {
586 self.modifier_capabilities()
587 .contains(NodeCapabilities::WINDOW_ROOT)
588 }
589
590 pub fn modifier_child_capabilities(&self) -> NodeCapabilities {
593 self.modifier_chain.aggregate_child_capabilities()
594 }
595
596 pub fn set_debug_modifiers(&mut self, enabled: bool) {
598 self.debug_modifiers.set(enabled);
599 self.modifier_chain.set_debug_logging(enabled);
600 }
601
602 pub fn debug_modifiers_enabled(&self) -> bool {
604 self.debug_modifiers.get()
605 }
606
607 pub fn modifier_locals_handle(&self) -> Option<ModifierLocalsHandle> {
610 self.modifier_chain.modifier_locals_handle()
611 }
612
613 pub fn has_layout_modifier_nodes(&self) -> bool {
615 self.modifier_capabilities()
616 .contains(NodeCapabilities::LAYOUT)
617 }
618
619 pub fn has_draw_modifier_nodes(&self) -> bool {
621 self.modifier_capabilities()
622 .contains(NodeCapabilities::DRAW)
623 }
624
625 pub fn has_pointer_input_modifier_nodes(&self) -> bool {
627 self.modifier_capabilities()
628 .contains(NodeCapabilities::POINTER_INPUT)
629 }
630
631 pub fn has_semantics_modifier_nodes(&self) -> bool {
633 self.modifier_capabilities()
634 .contains(NodeCapabilities::SEMANTICS)
635 }
636
637 pub fn has_focus_modifier_nodes(&self) -> bool {
639 self.modifier_capabilities()
640 .contains(NodeCapabilities::FOCUS)
641 }
642
643 fn refresh_registry_state(&self) {
644 if let (Some(id), Some(owner_context_id)) = (self.id.get(), self.owner_context_id.get()) {
645 let parent = self.parent();
646 let capabilities = self.modifier_child_capabilities();
647 let modifier_locals = self.modifier_locals_handle();
648 let _ = crate::render_state::with_layout_node_registry_by_app_context(
649 owner_context_id,
650 |registry| {
651 registry.update_entry(id, parent, capabilities, modifier_locals);
652 },
653 );
654 }
655 }
656
657 pub fn modifier_slices_snapshot(&self) -> Rc<ModifierNodeSlices> {
660 if self.modifier_slices_dirty.get() {
661 self.update_modifier_slices_cache();
662 }
663 self.modifier_slices_snapshot.get()
664 }
665
666 pub fn layout_state(&self) -> LayoutState {
668 *self.parts.layout_state().borrow()
669 }
670
671 pub fn measured_size(&self) -> Size {
673 self.parts.layout_state().borrow().size()
674 }
675
676 pub fn position(&self) -> Point {
678 self.parts.layout_state().borrow().position()
679 }
680
681 pub fn is_placed(&self) -> bool {
683 self.parts.layout_state().borrow().is_placed()
684 }
685
686 pub fn set_measured_size(&self, size: Size, context: &AppContext) {
690 self.parts
691 .layout_state()
692 .borrow_mut()
693 .set_size(size, context);
694 }
695
696 pub(crate) fn place(&self, at: ChildPlacement, placer: Option<NodeId>, context: &AppContext) {
700 self.parts
701 .layout_state()
702 .borrow_mut()
703 .place_child(at, placer, context);
704 }
705
706 pub fn set_content_offset(&self, offset: Point) {
708 self.parts
709 .layout_state()
710 .borrow_mut()
711 .set_content_offset(offset);
712 }
713
714 pub fn clear_placed(&self, context: &AppContext) {
716 self.parts.layout_state().borrow_mut().clear_placed(context);
717 }
718
719 fn note_semantics_layout_change(&self) {
720 if let Ok(mut state) = self.parts.layout_state().try_borrow_mut() {
721 state.note_semantics_change();
722 }
723 }
724
725 pub fn semantics_configuration(&self) -> Option<SemanticsConfiguration> {
727 crate::modifier::collect_semantics_from_chain(self.modifier_chain.chain())
728 }
729
730 fn forget_semantics_reach(&self) {
732 self.semantics_reach.set(None);
733 crate::modal_nodes::reach_changed(self.id.get());
734 }
735
736 pub fn semantics_reach(&self) -> cranpose_foundation::SemanticsReach {
738 if !self
740 .modifier_capabilities()
741 .contains(NodeCapabilities::SEMANTICS)
742 {
743 return cranpose_foundation::SemanticsReach::default();
744 }
745 if let Some(reach) = self.semantics_reach.get() {
746 return reach;
747 }
748 let reach = crate::modifier::semantics_reach_of_chain(self.modifier_chain.chain());
749 self.semantics_reach.set(Some(reach));
750 reach
751 }
752
753 pub(crate) fn modifier_chain(&self) -> &ModifierChainHandle {
754 &self.modifier_chain
755 }
756
757 pub fn with_layout_state<R>(&self, read: impl FnOnce(&LayoutState) -> R) -> R {
759 read(&self.parts.layout_state().borrow())
760 }
761
762 pub(crate) fn layout_parts(&self) -> &Rc<LayoutParts> {
763 &self.parts
764 }
765
766 pub(crate) fn layout_runtime_state(&self) -> &RefCell<LayoutRuntimeState> {
767 self.parts.runtime_state()
768 }
769
770 #[cfg(test)]
771 pub(crate) fn layout_runtime_debug_stats(&self) -> LayoutRuntimeDebugStats {
772 self.parts.runtime_state().borrow().debug_stats()
773 }
774}
775impl Clone for LayoutNode {
776 fn clone(&self) -> Self {
777 let mut node = Self {
778 #[cfg(feature = "inspection")]
779 source_trace: Rc::clone(&self.source_trace),
780 modifier: self.modifier.clone(),
781 modifier_chain: ModifierChainHandle::for_layout_direction(
782 self.modifier_chain.layout_direction(),
783 ),
784 measure_policy: Rc::clone(&self.measure_policy),
785 density: self.density,
786 children: self.children.clone(),
787 needs_semantics: Cell::new(self.needs_semantics.get()),
788 descendant_needs_semantics: Cell::new(self.descendant_needs_semantics.get()),
789 semantics_reach: Cell::new(None),
790 needs_redraw: Cell::new(self.needs_redraw.get()),
791 needs_pointer_pass: Cell::new(self.needs_pointer_pass.get()),
792 needs_focus_sync: Cell::new(self.needs_focus_sync.get()),
793 parent: NodeIdCell::new(self.parent.get()),
794 folded_parent: NodeIdCell::new(self.folded_parent.get()),
795 id: NodeIdCell::new(None),
796 owner_context_id: Cell::new(None),
797 debug_modifiers: Cell::new(self.debug_modifiers.get()),
798 is_virtual: self.is_virtual,
799 modifier_slices_snapshot: crate::modifier::SlicesSnapshot::default(),
800 modifier_slices_dirty: Cell::new(true),
801 parts: Rc::clone(&self.parts),
802 };
803 node.sync_modifier_chain(None);
804 node
805 }
806}
807
808impl Node for LayoutNode {
809 fn mount(&mut self) {
810 self.modifier_chain.remount(self.id.get());
811 crate::modal_nodes::reach_changed(self.id.get());
812 }
813
814 fn unmount(&mut self) {
815 self.modifier_chain.chain_mut().detach_nodes();
816 }
817
818 fn set_node_id(&mut self, id: NodeId) {
819 Self::set_node_id(self, id);
820 }
821
822 fn insert_child(&mut self, child: NodeId) -> bool {
823 if self.children.contains(&child) {
824 return false;
825 }
826 self.children.push(child);
827 self.parts.cache().clear();
828 self.mark_needs_measure();
829 self.note_semantics_layout_change();
830 true
831 }
832
833 fn remove_child(&mut self, child: NodeId) -> bool {
834 let before = self.children.len();
835 self.children.retain(|&id| id != child);
836 let removed = self.children.len() < before;
837 if removed {
838 self.parts.cache().clear();
839 self.mark_needs_measure();
840 self.note_semantics_layout_change();
841 }
842 removed
843 }
844
845 fn move_child(&mut self, from: usize, to: usize) {
846 if from == to || from >= self.children.len() {
847 return;
848 }
849 let child = self.children.remove(from);
850 let target = to.min(self.children.len());
851 self.children.insert(target, child);
852 self.parts.cache().clear();
853 self.mark_needs_measure();
854 self.note_semantics_layout_change();
855 }
856
857 fn update_children(&mut self, children: &[NodeId]) {
858 self.children.clear();
859 self.children.extend_from_slice(children);
860 self.parts.cache().clear();
861 self.mark_needs_measure();
862 self.note_semantics_layout_change();
863 }
864
865 fn collect_children_into(&self, out: &mut smallvec::SmallVec<[NodeId; 8]>) {
866 out.clear();
867 out.extend_from_slice(&self.children);
868 }
869
870 fn for_each_child(&self, f: &mut dyn FnMut(NodeId)) {
871 for &child in &self.children {
872 f(child);
873 }
874 }
875
876 fn owned_child_index(&self, child: NodeId) -> Option<usize> {
877 self.children.iter().position(|&id| id == child)
878 }
879
880 fn on_attached_to_parent(&mut self, parent: NodeId) {
881 self.set_parent(parent);
882 }
883
884 fn on_removed_from_parent(&mut self) {
885 self.clear_parent();
886 }
887
888 fn parent(&self) -> Option<NodeId> {
889 self.parent.get()
890 }
891
892 fn mark_needs_layout(&self) {
893 Self::mark_needs_layout(self);
894 }
895
896 fn needs_layout(&self) -> bool {
897 Self::needs_layout(self)
898 }
899
900 fn mark_needs_measure(&self) {
901 Self::mark_needs_measure(self);
902 }
903
904 fn needs_measure(&self) -> bool {
905 Self::needs_measure(self)
906 }
907
908 fn mark_descendant_needs_layout(&self, measure: bool) {
909 self.parts.cache().mark_descendant_needs_layout(measure);
910 }
911
912 fn descendant_needs_layout(&self) -> bool {
913 self.parts.cache().dirt().descendant.layout
914 }
915
916 fn is_virtual(&self) -> bool {
917 self.is_virtual
918 }
919
920 fn descendant_needs_measure(&self) -> bool {
921 self.parts.cache().dirt().descendant.measure
922 }
923
924 fn mark_needs_semantics(&self) {
925 self.needs_semantics.set(true);
926 self.forget_semantics_reach();
927 }
928
929 fn mark_descendant_needs_semantics(&self) {
930 self.descendant_needs_semantics.set(true);
931 }
932
933 fn needs_semantics(&self) -> bool {
934 Self::needs_semantics(self)
935 }
936
937 fn set_parent_for_bubbling(&mut self, parent: NodeId) {
938 if self.parent.get().is_none() {
939 self.parent.set(Some(parent));
940 }
941 }
942
943 fn recycle_key(&self) -> Option<TypeId> {
944 Some(TypeId::of::<Self>())
945 }
946
947 fn recycle_pool_limit(&self) -> Option<usize> {
948 Some(super::node_pool_limit::node_pool_limit())
949 }
950
951 fn prepare_for_recycle(&mut self) {
952 *self = Self::new_recycled_shell(self.is_virtual);
953 }
954
955 fn rehouse_for_recycle(&self) -> Option<Box<dyn Node>> {
956 Some(Box::new(Self::new_recycled_shell(self.is_virtual)))
957 }
958
959 fn rehouse_for_live_compaction(&mut self) -> Option<Box<dyn Node>> {
960 let mut node = std::mem::replace(self, Self::new_recycled_shell(self.is_virtual));
966 node.children.shrink_to_fit();
967 Some(Box::new(node))
968 }
969}
970
971impl Drop for LayoutNode {
972 fn drop(&mut self) {
973 self.parts.cache().advance_revision();
974 if let (Some(id), Some(owner_context_id)) = (self.id.get(), self.owner_context_id.get()) {
975 unregister_layout_node(owner_context_id, id);
976 }
977 }
978}
979
980#[cfg(test)]
981#[path = "tests/layout_node_tests.rs"]
982mod tests;