1use std::{
2 collections::HashMap,
3 ops::{Add, AddAssign},
4 sync::Arc,
5};
6
7use indextree::NodeId;
8use rustc_hash::FxHashMap;
9use tracing::debug;
10use winit::window::CursorIcon;
11
12use crate::{
13 Px,
14 accessibility::{AccessibilityActionHandler, AccessibilityNode},
15 cursor::{CursorEventContent, PointerChange},
16 focus::{
17 FocusDirection, FocusRegistration, FocusRequester, FocusRevealRequest, FocusState,
18 FocusTraversalPolicy,
19 },
20 layout::{LayoutInput, LayoutPolicyDyn, LayoutResult, PlacementScope, RenderPolicyDyn},
21 modifier::{
22 LayoutModifierChild, LayoutModifierInput, LayoutModifierNode, Modifier,
23 OrderedModifierAction,
24 },
25 prop::CallbackWith,
26 px::{PxPosition, PxSize},
27 render_graph::RenderFragment,
28 runtime::{
29 RuntimePhase, push_current_component_instance_key,
30 push_current_node_with_instance_logic_id, push_phase,
31 },
32 time::Instant,
33};
34
35use super::{
36 LayoutContext, LayoutSnapshotEntry,
37 constraint::{Constraint, ParentConstraint},
38 nearest_replay_boundary_instance_key,
39};
40
41#[cfg(feature = "profiling")]
42use crate::profiler::{Phase as ProfilerPhase, ScopeGuard as ProfilerScopeGuard};
43
44#[derive(Clone, Copy, Debug, Eq, PartialEq)]
47pub(crate) enum NodeRole {
48 Composition,
49 Layout,
50}
51
52pub(crate) struct ComponentNode {
53 pub(crate) fn_name: String,
55 pub(crate) role: NodeRole,
58 pub(crate) instance_logic_id: u64,
60 pub(crate) instance_key: u64,
62 pub(crate) pointer_preview_handlers: Vec<Box<PointerInputHandlerFn>>,
64 pub(crate) pointer_handlers: Vec<Box<PointerInputHandlerFn>>,
66 pub(crate) pointer_final_handlers: Vec<Box<PointerInputHandlerFn>>,
68 pub(crate) keyboard_preview_handlers: Vec<Box<KeyboardInputHandlerFn>>,
70 pub(crate) keyboard_handlers: Vec<Box<KeyboardInputHandlerFn>>,
72 pub(crate) ime_preview_handlers: Vec<Box<ImeInputHandlerFn>>,
74 pub(crate) ime_handlers: Vec<Box<ImeInputHandlerFn>>,
76 pub(crate) focus_requester_binding: Option<FocusRequester>,
78 pub(crate) focus_registration: Option<FocusRegistration>,
80 pub(crate) focus_restorer_fallback: Option<FocusRequester>,
82 pub(crate) focus_traversal_policy: Option<FocusTraversalPolicy>,
85 pub(crate) focus_changed_handler: Option<FocusChangedHandler>,
87 pub(crate) focus_event_handler: Option<FocusEventHandler>,
89 pub(crate) focus_beyond_bounds_handler: Option<FocusBeyondBoundsHandler>,
91 pub(crate) focus_reveal_handler: Option<FocusRevealHandler>,
94 pub(crate) modifier: Modifier,
96 pub(crate) layout_policy: Box<dyn LayoutPolicyDyn>,
98 pub(crate) render_policy: Box<dyn RenderPolicyDyn>,
100 pub(crate) replay: Option<crate::prop::ComponentReplayData>,
102 pub(crate) props_unchanged_from_previous: bool,
104}
105
106pub(crate) struct ComponentNodeMetaData {
108 pub computed_data: Option<ComputedData>,
111 pub layout_cache_hit: bool,
113 pub placement_order: Option<u64>,
115 pub rel_position: Option<PxPosition>,
118 pub base_abs_position: Option<PxPosition>,
123 pub abs_position: Option<PxPosition>,
128 pub event_clip_rect: Option<crate::PxRect>,
131 pub(crate) fragment: RenderFragment,
136 pub clips_children: bool,
138 pub opacity: f32,
140 pub accessibility: Option<AccessibilityNode>,
142 pub accessibility_action_handler: Option<AccessibilityActionHandler>,
144}
145
146impl ComponentNodeMetaData {
147 pub fn none() -> Self {
149 Self {
150 computed_data: None,
151 layout_cache_hit: false,
152 placement_order: None,
153 rel_position: None,
154 base_abs_position: None,
155 abs_position: None,
156 event_clip_rect: None,
157 fragment: RenderFragment::default(),
158 clips_children: false,
159 opacity: 1.0,
160 accessibility: None,
161 accessibility_action_handler: None,
162 }
163 }
164
165 pub fn fragment_mut(&mut self) -> &mut RenderFragment {
167 &mut self.fragment
168 }
169
170 pub(crate) fn take_fragment(&mut self) -> RenderFragment {
172 std::mem::take(&mut self.fragment)
173 }
174}
175
176impl Default for ComponentNodeMetaData {
177 fn default() -> Self {
178 Self::none()
179 }
180}
181
182pub(crate) fn direct_layout_children(node_id: NodeId, tree: &ComponentNodeTree) -> Vec<NodeId> {
183 fn collect(node_id: NodeId, tree: &ComponentNodeTree, output: &mut Vec<NodeId>) {
184 let Some(node_ref) = tree.get(node_id) else {
185 return;
186 };
187 if node_ref.get().role == NodeRole::Layout {
188 output.push(node_id);
189 return;
190 }
191
192 for child_id in node_id.children(tree) {
193 collect(child_id, tree, output);
194 }
195 }
196
197 let mut children = Vec::new();
198 for child_id in node_id.children(tree) {
199 collect(child_id, tree, &mut children);
200 }
201 children
202}
203
204fn reset_frame_metadata(node_id: NodeId, component_node_metadatas: &mut ComponentNodeMetaDatas) {
205 let metadata = component_node_metadatas.entry_or_default(node_id);
206 metadata.computed_data = None;
207 metadata.layout_cache_hit = false;
208 metadata.placement_order = None;
209 metadata.rel_position = None;
210 metadata.base_abs_position = None;
211 metadata.abs_position = None;
212 metadata.event_clip_rect = None;
213 metadata.fragment = RenderFragment::default();
214 metadata.clips_children = false;
215 metadata.opacity = 1.0;
216}
217
218pub(crate) type ComponentNodeTree = indextree::Arena<ComponentNode>;
220
221#[derive(Default)]
223pub(crate) struct ComponentNodeMetaDatas {
224 entries: FxHashMap<NodeId, ComponentNodeMetaData>,
225}
226
227impl ComponentNodeMetaDatas {
228 pub(crate) fn new() -> Self {
229 Self::default()
230 }
231
232 pub(crate) fn clear(&mut self) {
233 self.entries.clear();
234 }
235
236 pub(crate) fn insert(
237 &mut self,
238 node_id: NodeId,
239 metadata: ComponentNodeMetaData,
240 ) -> Option<ComponentNodeMetaData> {
241 self.entries.insert(node_id, metadata)
242 }
243
244 pub(crate) fn remove(&mut self, node_id: &NodeId) -> Option<ComponentNodeMetaData> {
245 self.entries.remove(node_id)
246 }
247
248 pub(crate) fn get(&self, node_id: &NodeId) -> Option<&ComponentNodeMetaData> {
249 self.entries.get(node_id)
250 }
251
252 pub(crate) fn get_mut(&mut self, node_id: &NodeId) -> Option<&mut ComponentNodeMetaData> {
253 self.entries.get_mut(node_id)
254 }
255
256 pub(crate) fn entry_or_default(&mut self, node_id: NodeId) -> &mut ComponentNodeMetaData {
257 self.entries.entry(node_id).or_default()
258 }
259
260 #[cfg(feature = "testing")]
261 pub(crate) fn with_entries<R>(
262 &self,
263 f: impl FnOnce(&FxHashMap<NodeId, ComponentNodeMetaData>) -> R,
264 ) -> R {
265 f(&self.entries)
266 }
267}
268
269#[derive(Debug, Clone, PartialEq)]
271pub enum MeasurementError {
272 NodeNotFoundInTree,
274 NodeNotFoundInMeta,
277 MeasureFnFailed(String),
280 ChildMeasurementFailed(NodeId),
284}
285
286#[derive(Debug, Clone, Copy, PartialEq, Eq)]
288pub enum PointerEventPass {
289 Initial,
291 Main,
293 Final,
295}
296
297pub type PointerInputHandlerFn = dyn Fn(PointerInput) + Send + Sync;
299pub type KeyboardInputHandlerFn = dyn Fn(KeyboardInput) + Send + Sync;
301pub type ImeInputHandlerFn = dyn Fn(ImeInput) + Send + Sync;
303pub type FocusChangedHandler = CallbackWith<FocusState>;
305pub type FocusEventHandler = CallbackWith<FocusState>;
307pub type FocusBeyondBoundsHandler = CallbackWith<FocusDirection, bool>;
309pub type FocusRevealHandler = CallbackWith<FocusRevealRequest, bool>;
311
312pub struct PointerInput<'a> {
319 pub pass: PointerEventPass,
321 pub computed_data: ComputedData,
323 pub cursor_position_rel: Option<PxPosition>,
326 pub(crate) cursor_position_abs: &'a mut Option<PxPosition>,
328 pub pointer_changes: &'a mut Vec<PointerChange>,
330 pub key_modifiers: winit::keyboard::ModifiersState,
332 pub(crate) ime_request: &'a mut Option<ImeRequest>,
333 pub(crate) request_window_drag: &'a mut bool,
334}
335
336impl PointerInput<'_> {
337 pub fn consume_pointer_changes(&mut self) {
339 for change in self.pointer_changes.iter_mut() {
340 change.consume();
341 }
342 }
343
344 pub fn has_unconsumed_release(&self) -> bool {
346 self.pointer_changes.iter().any(|change| {
347 !change.is_consumed() && matches!(change.content, CursorEventContent::Released(_))
348 })
349 }
350
351 pub fn cursor_position_abs(&self) -> Option<PxPosition> {
353 *self.cursor_position_abs
354 }
355
356 pub fn block_cursor(&mut self) {
358 self.cursor_position_abs.take();
359 self.consume_pointer_changes();
360 }
361
362 pub fn block_all(&mut self) {
364 self.block_cursor();
365 }
366
367 pub fn drag_window(&mut self) {
369 *self.request_window_drag = true;
370 }
371
372 pub fn ime_session(&mut self) -> ImeSession<'_> {
374 ImeSession {
375 request: self.ime_request,
376 }
377 }
378}
379
380pub struct KeyboardInput<'a> {
386 pub computed_data: ComputedData,
388 pub keyboard_events: &'a mut Vec<winit::event::KeyEvent>,
390 pub key_modifiers: winit::keyboard::ModifiersState,
392 pub(crate) ime_request: &'a mut Option<ImeRequest>,
393}
394
395impl KeyboardInput<'_> {
396 pub fn block_keyboard(&mut self) {
398 self.keyboard_events.clear();
399 }
400
401 pub fn ime_session(&mut self) -> ImeSession<'_> {
403 ImeSession {
404 request: self.ime_request,
405 }
406 }
407}
408
409pub struct ImeInput<'a> {
414 pub computed_data: ComputedData,
416 pub ime_events: &'a mut Vec<winit::event::Ime>,
418 pub(crate) ime_request: &'a mut Option<ImeRequest>,
419}
420
421impl ImeInput<'_> {
422 pub fn block_ime(&mut self) {
424 self.ime_events.clear();
425 }
426
427 pub fn ime_session(&mut self) -> ImeSession<'_> {
429 ImeSession {
430 request: self.ime_request,
431 }
432 }
433}
434
435#[derive(Default, Debug)]
439pub(crate) struct WindowRequests {
440 pub cursor_icon: CursorIcon,
444 pub ime_request: Option<ImeRequest>,
449 pub request_window_drag: bool,
451}
452
453pub struct ImeSession<'a> {
459 request: &'a mut Option<ImeRequest>,
460}
461
462impl ImeSession<'_> {
463 pub fn update(&mut self, request: ImeRequest) {
465 *self.request = Some(request);
466 }
467
468 pub fn clear(&mut self) {
470 *self.request = None;
471 }
472}
473
474#[derive(Clone, Debug, PartialEq, Eq)]
477pub struct ImeRequest {
478 pub size: PxSize,
480 pub local_position: PxPosition,
482 pub selection_range: Option<std::ops::Range<usize>>,
484 pub composition_range: Option<std::ops::Range<usize>>,
486 pub(crate) position: Option<PxPosition>, }
490
491impl ImeRequest {
492 pub fn new(size: PxSize) -> Self {
496 Self {
497 size,
498 local_position: PxPosition::ZERO,
499 selection_range: None,
500 composition_range: None,
501 position: None, }
503 }
504
505 pub fn with_local_position(mut self, local_position: PxPosition) -> Self {
507 self.local_position = local_position;
508 self
509 }
510
511 pub fn with_selection_range(mut self, selection_range: Option<std::ops::Range<usize>>) -> Self {
513 self.selection_range = selection_range;
514 self
515 }
516
517 pub fn with_composition_range(
519 mut self,
520 composition_range: Option<std::ops::Range<usize>>,
521 ) -> Self {
522 self.composition_range = composition_range;
523 self
524 }
525}
526
527fn apply_layout_placements(
528 placements: &[(u64, PxPosition)],
529 tree: &ComponentNodeTree,
530 children: &[NodeId],
531 component_node_metadatas: &mut ComponentNodeMetaDatas,
532) {
533 if placements.is_empty() || children.is_empty() {
534 return;
535 }
536 let mut child_map = HashMap::new();
537 for child_id in children {
538 if let Some(child) = tree.get(*child_id) {
539 child_map.insert(child.get().instance_key, *child_id);
540 }
541 }
542 for (placement_order, (instance_key, position)) in placements.iter().enumerate() {
543 if let Some(child_id) = child_map.get(instance_key) {
544 place_node(
545 *child_id,
546 *position,
547 placement_order as u64,
548 component_node_metadatas,
549 );
550 }
551 }
552}
553
554fn restore_cached_subtree_metadata(
555 node_id: NodeId,
556 rel_position: Option<PxPosition>,
557 tree: &ComponentNodeTree,
558 component_node_metadatas: &mut ComponentNodeMetaDatas,
559 layout_ctx: &LayoutContext<'_>,
560) -> bool {
561 let Some(node) = tree.get(node_id) else {
562 return false;
563 };
564 let instance_key = node.get().instance_key;
565 let Some(entry) = layout_ctx.snapshot(instance_key) else {
566 return false;
567 };
568
569 let size = entry.layout_result.size;
570 let placements = entry.layout_result.placements.clone();
571
572 {
573 let metadata = component_node_metadatas.entry_or_default(node_id);
574 metadata.computed_data = Some(size);
575 metadata.layout_cache_hit = true;
576 if let Some(position) = rel_position {
577 metadata.rel_position = Some(position);
578 }
579 }
580
581 let mut child_positions = HashMap::new();
582 let mut child_orders = HashMap::new();
583 for (placement_order, (child_key, child_pos)) in placements.into_iter().enumerate() {
584 child_positions.insert(child_key, child_pos);
585 child_orders.insert(child_key, placement_order as u64);
586 }
587
588 for child_id in node_id.children(tree) {
589 let child_layout = tree.get(child_id).map(|child| {
590 let instance_key = child.get().instance_key;
591 (
592 child_positions.get(&instance_key).copied(),
593 child_orders.get(&instance_key).copied(),
594 )
595 });
596 let (child_rel_position, child_placement_order) = child_layout.unwrap_or((None, None));
597 if let Some(placement_order) = child_placement_order {
598 component_node_metadatas
599 .entry_or_default(child_id)
600 .placement_order = Some(placement_order);
601 }
602 if !restore_cached_subtree_metadata(
603 child_id,
604 child_rel_position,
605 tree,
606 component_node_metadatas,
607 layout_ctx,
608 ) {
609 return false;
610 }
611 }
612
613 true
614}
615
616#[derive(Clone)]
617struct MeasuredNodeLayout {
618 size: ComputedData,
619 placements: Vec<(u64, PxPosition)>,
620 measured_children: HashMap<NodeId, crate::layout::ChildMeasure>,
621}
622
623struct MeasureLayoutContext<'a, 'ctx> {
624 tree: &'a ComponentNodeTree,
625 children: &'a [NodeId],
626 component_node_metadatas: *mut ComponentNodeMetaDatas,
627 layout_ctx: Option<&'a LayoutContext<'ctx>>,
628}
629
630fn measure_base_layout(
631 layout_policy: &dyn LayoutPolicyDyn,
632 layout_ctx: &MeasureLayoutContext<'_, '_>,
633 constraint: &Constraint,
634) -> Result<MeasuredNodeLayout, MeasurementError> {
635 let input = LayoutInput::new(
636 layout_ctx.tree,
637 ParentConstraint::new(constraint),
638 layout_ctx.children,
639 layout_ctx.component_node_metadatas,
640 layout_ctx.layout_ctx,
641 );
642 let scope = input.measure_scope();
643 let layout_result = layout_policy.measure_dyn(&scope)?;
644 Ok(MeasuredNodeLayout {
645 size: layout_result.size,
646 placements: layout_result.placements,
647 measured_children: input.take_measured_children(),
648 })
649}
650
651fn measure_with_layout_modifiers(
652 modifiers: &[Arc<dyn LayoutModifierNode>],
653 layout_policy: &dyn LayoutPolicyDyn,
654 layout_ctx: &MeasureLayoutContext<'_, '_>,
655 constraint: &Constraint,
656) -> Result<MeasuredNodeLayout, MeasurementError> {
657 if modifiers.is_empty() {
658 return measure_base_layout(layout_policy, layout_ctx, constraint);
659 }
660
661 struct ModifierChildRunner<'a, 'b> {
662 next: &'b mut dyn FnMut(&Constraint) -> Result<MeasuredNodeLayout, MeasurementError>,
663 last: Option<MeasuredNodeLayout>,
664 placements: Vec<(u64, PxPosition)>,
665 _marker: std::marker::PhantomData<&'a ()>,
666 }
667
668 impl LayoutModifierChild for ModifierChildRunner<'_, '_> {
669 fn measure(&mut self, constraint: &Constraint) -> Result<ComputedData, MeasurementError> {
670 let measured = (self.next)(constraint)?;
671 let size = measured.size;
672 self.last = Some(measured);
673 Ok(size)
674 }
675
676 fn place(&mut self, position: PxPosition) {
677 let measured = self
678 .last
679 .as_ref()
680 .expect("layout modifier child must be measured before placement");
681 for (instance_key, child_position) in &measured.placements {
682 self.placements
683 .push((*instance_key, position + *child_position));
684 }
685 }
686 }
687
688 let head = &modifiers[0];
689 let tail = &modifiers[1..];
690 let mut next = |next_constraint: &Constraint| {
691 measure_with_layout_modifiers(tail, layout_policy, layout_ctx, next_constraint)
692 };
693 let input = LayoutInput::new(
694 layout_ctx.tree,
695 ParentConstraint::new(constraint),
696 layout_ctx.children,
697 layout_ctx.component_node_metadatas,
698 layout_ctx.layout_ctx,
699 );
700 let modifier_input = LayoutModifierInput {
701 layout_input: &input,
702 };
703 let mut child = ModifierChildRunner {
704 next: &mut next,
705 last: None,
706 placements: Vec::new(),
707 _marker: std::marker::PhantomData,
708 };
709 let size = head.measure(&modifier_input, &mut child)?.size;
710 if let Some(measured) = child.last.as_ref() {
711 input.extend_measured_children(measured.measured_children.clone());
712 }
713 Ok(MeasuredNodeLayout {
714 size,
715 placements: child.placements,
716 measured_children: input.take_measured_children(),
717 })
718}
719
720fn relayout_base_layout(
721 layout_policy: &dyn LayoutPolicyDyn,
722 tree: &ComponentNodeTree,
723 children: &[NodeId],
724 cached_child_sizes: &[ComputedData],
725 constraint: &Constraint,
726 cached_size: ComputedData,
727) -> Option<Vec<(u64, PxPosition)>> {
728 if cached_child_sizes.len() != children.len() {
729 return None;
730 }
731
732 let child_sizes: HashMap<NodeId, ComputedData> = children
733 .iter()
734 .copied()
735 .zip(cached_child_sizes.iter().copied())
736 .collect();
737 let scope = PlacementScope::new(
738 tree,
739 ParentConstraint::new(constraint),
740 children,
741 &child_sizes,
742 cached_size,
743 );
744 layout_policy.place_children_dyn(&scope)
745}
746
747pub(crate) fn measure_node(
749 node_id: NodeId,
750 parent_constraint: &Constraint,
751 tree: &ComponentNodeTree,
752 component_node_metadatas: &mut ComponentNodeMetaDatas,
753 layout_ctx: Option<&LayoutContext<'_>>,
754) -> Result<ComputedData, MeasurementError> {
755 let node_data_ref = tree
756 .get(node_id)
757 .ok_or(MeasurementError::NodeNotFoundInTree)?;
758 let node_data = node_data_ref.get();
759 #[cfg(feature = "profiling")]
760 let mut profiler_guard = Some(ProfilerScopeGuard::new(
761 ProfilerPhase::Measure,
762 Some(node_id),
763 node_data_ref.parent(),
764 Some(node_data.fn_name.as_str()),
765 ));
766
767 let children = direct_layout_children(node_id, tree);
768 let timer = Instant::now();
769
770 debug!(
771 "Measuring node {} with {} children, parent constraint: {:?}",
772 node_data.fn_name,
773 children.len(),
774 parent_constraint
775 );
776
777 let _node_ctx_guard = push_current_node_with_instance_logic_id(
780 node_id,
781 node_data.instance_logic_id,
782 node_data.fn_name.as_str(),
783 );
784 let replay_boundary_instance_key = nearest_replay_boundary_instance_key(node_id, tree);
785 let _instance_ctx_guard = push_current_component_instance_key(replay_boundary_instance_key);
786 let _phase_guard = push_phase(RuntimePhase::Measure);
787
788 let layout_policy = &node_data.layout_policy;
789 let layout_modifiers: Vec<_> = node_data
790 .modifier
791 .ordered_actions()
792 .into_iter()
793 .filter_map(|action| match action {
794 OrderedModifierAction::Layout(node) => Some(node.node()),
795 _ => None,
796 })
797 .collect();
798 if let Some(layout_ctx) = layout_ctx {
799 layout_ctx.inc_measure_node_calls();
800 if let Some(entry) = layout_ctx.snapshot(node_data.instance_key) {
801 let same_constraint = entry.constraint_key == *parent_constraint;
802 let node_self_measure_dirty = layout_ctx
803 .measure_self_nodes
804 .contains(&node_data.instance_key);
805 let node_self_placement_dirty = layout_ctx
806 .placement_self_nodes
807 .contains(&node_data.instance_key);
808 let node_effective_dirty = layout_ctx
809 .dirty_effective_nodes
810 .contains(&node_data.instance_key);
811 let has_all_child_constraints = entry.child_constraints.len() == children.len();
812 let has_all_child_sizes = entry.child_sizes.len() == children.len();
813 let can_try_reuse = same_constraint
814 && !node_self_measure_dirty
815 && has_all_child_constraints
816 && (!node_effective_dirty || has_all_child_sizes);
817 if can_try_reuse {
818 let cached_result = entry.layout_result.clone();
819 let cached_child_constraints = entry.child_constraints.clone();
820 let cached_child_sizes = entry.child_sizes.clone();
821
822 if !node_effective_dirty
823 && restore_cached_subtree_metadata(
824 node_id,
825 None,
826 tree,
827 component_node_metadatas,
828 layout_ctx,
829 )
830 {
831 apply_layout_placements(
832 &cached_result.placements,
833 tree,
834 &children,
835 component_node_metadatas,
836 );
837 layout_ctx.inc_cache_hit_direct();
838 return Ok(cached_result.size);
839 }
840
841 let dirty_children: Vec<(usize, NodeId, Constraint)> = children
842 .iter()
843 .enumerate()
844 .filter_map(|(index, child_id)| {
845 tree.get(*child_id).and_then(|child| {
846 if layout_ctx
847 .dirty_effective_nodes
848 .contains(&child.get().instance_key)
849 {
850 Some((index, *child_id, cached_child_constraints[index]))
851 } else {
852 None
853 }
854 })
855 })
856 .collect();
857
858 let mut child_size_changed = false;
859 for (index, child_id, _constraint) in &dirty_children {
860 let size = measure_node(
861 *child_id,
862 &cached_child_constraints[*index],
863 tree,
864 component_node_metadatas,
865 Some(layout_ctx),
866 )?;
867 if size != cached_child_sizes[*index] {
868 child_size_changed = true;
869 break;
870 }
871 }
872 if child_size_changed {
873 layout_ctx.inc_cache_miss_child_size();
874 } else {
875 let mut restored = true;
876 for child_id in &children {
877 let Some(child) = tree.get(*child_id) else {
878 restored = false;
879 break;
880 };
881 if layout_ctx
882 .dirty_effective_nodes
883 .contains(&child.get().instance_key)
884 {
885 continue;
886 }
887 if !restore_cached_subtree_metadata(
888 *child_id,
889 None,
890 tree,
891 component_node_metadatas,
892 layout_ctx,
893 ) {
894 restored = false;
895 break;
896 }
897 }
898 if restored {
899 reset_frame_metadata(node_id, component_node_metadatas);
900 let placements = if node_self_placement_dirty {
901 match relayout_base_layout(
902 layout_policy.as_ref(),
903 tree,
904 &children,
905 &cached_child_sizes,
906 parent_constraint,
907 cached_result.size,
908 ) {
909 Some(placements) => placements,
910 None => {
911 layout_ctx.inc_cache_miss_dirty_self();
912 Vec::new()
915 }
916 }
917 } else {
918 cached_result.placements.clone()
919 };
920 if node_self_placement_dirty && placements.is_empty() {
921 } else {
923 apply_layout_placements(
924 &placements,
925 tree,
926 &children,
927 component_node_metadatas,
928 );
929 if let Some(metadata) = component_node_metadatas.get_mut(&node_id) {
930 metadata.computed_data = Some(cached_result.size);
931 metadata.layout_cache_hit = true;
932 }
933 if node_self_placement_dirty {
934 layout_ctx.insert_snapshot(
935 node_data.instance_key,
936 LayoutSnapshotEntry {
937 constraint_key: *parent_constraint,
938 layout_result: LayoutResult {
939 size: cached_result.size,
940 placements,
941 },
942 child_constraints: cached_child_constraints,
943 child_sizes: cached_child_sizes,
944 },
945 );
946 }
947 layout_ctx.inc_cache_hit_boundary();
948 return Ok(cached_result.size);
949 }
950 }
951 }
952 }
953 if !same_constraint {
954 layout_ctx.inc_cache_miss_constraint();
955 } else if node_self_measure_dirty || node_self_placement_dirty {
956 layout_ctx.inc_cache_miss_dirty_self();
957 } else if node_effective_dirty {
958 layout_ctx.inc_cache_miss_child_size();
959 } else {
960 layout_ctx.inc_cache_miss_no_entry();
961 }
962 } else {
963 layout_ctx.inc_cache_miss_no_entry();
964 }
965 }
966
967 reset_frame_metadata(node_id, component_node_metadatas);
968 let measure_layout_ctx = MeasureLayoutContext {
969 tree,
970 children: &children,
971 component_node_metadatas,
972 layout_ctx,
973 };
974 let measured = measure_with_layout_modifiers(
975 &layout_modifiers,
976 layout_policy.as_ref(),
977 &measure_layout_ctx,
978 parent_constraint,
979 )?;
980 let size = measured.size;
981 let measured_children = measured.measured_children;
982 let placements = measured.placements;
983 apply_layout_placements(&placements, tree, &children, component_node_metadatas);
984
985 component_node_metadatas
986 .entry_or_default(node_id)
987 .computed_data = Some(size);
988
989 #[cfg(feature = "profiling")]
990 if let Some(guard) = &mut profiler_guard {
991 guard.set_computed_size(size.width.0, size.height.0);
992 }
993
994 if let Some(layout_ctx) = layout_ctx {
995 let mut cacheable = true;
996 let mut child_constraints = Vec::with_capacity(children.len());
997 let mut child_sizes = Vec::with_capacity(children.len());
998 for child_id in &children {
999 let Some(measurement) = measured_children.get(child_id) else {
1000 cacheable = false;
1001 break;
1002 };
1003 if !measurement.consistent {
1004 cacheable = false;
1005 break;
1006 }
1007 child_constraints.push(measurement.constraint);
1008 child_sizes.push(measurement.size);
1009 }
1010 if cacheable {
1011 let layout_result = LayoutResult { size, placements };
1012 layout_ctx.insert_snapshot(
1013 node_data.instance_key,
1014 LayoutSnapshotEntry {
1015 constraint_key: *parent_constraint,
1016 layout_result,
1017 child_constraints,
1018 child_sizes,
1019 },
1020 );
1021 layout_ctx.inc_cache_store_count();
1022 } else {
1023 layout_ctx.remove_snapshot(node_data.instance_key);
1024 layout_ctx.inc_cache_drop_non_cacheable_count();
1025 }
1026 }
1027
1028 debug!(
1029 "Measured node {} in {:?} with size {:?}",
1030 node_data.fn_name,
1031 timer.elapsed(),
1032 size
1033 );
1034
1035 #[cfg(feature = "profiling")]
1036 if let Some(guard) = &mut profiler_guard {
1037 guard.set_computed_size(size.width.0, size.height.0);
1038 }
1039
1040 Ok(size)
1041}
1042
1043pub(crate) fn place_node(
1045 node: indextree::NodeId,
1046 rel_position: PxPosition,
1047 placement_order: u64,
1048 component_node_metadatas: &mut ComponentNodeMetaDatas,
1049) {
1050 let metadata = component_node_metadatas.entry_or_default(node);
1051 metadata.rel_position = Some(rel_position);
1052 metadata.placement_order = Some(placement_order);
1053}
1054
1055#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1058pub struct ComputedData {
1059 pub width: Px,
1061 pub height: Px,
1063}
1064
1065impl Add for ComputedData {
1066 type Output = Self;
1067 fn add(self, rhs: Self) -> Self::Output {
1068 Self {
1069 width: self.width + rhs.width,
1070 height: self.height + rhs.height,
1071 }
1072 }
1073}
1074
1075impl AddAssign for ComputedData {
1076 fn add_assign(&mut self, rhs: Self) {
1077 *self = *self + rhs;
1078 }
1079}
1080
1081impl ComputedData {
1082 pub const ZERO: Self = Self {
1084 width: Px(0),
1085 height: Px(0),
1086 };
1087
1088 pub fn min_from_constraint(constraint: &Constraint) -> Self {
1090 let width = constraint.width.min;
1091 let height = constraint.height.min;
1092 Self { width, height }
1093 }
1094
1095 pub fn min(self, rhs: Self) -> Self {
1097 Self {
1098 width: self.width.min(rhs.width),
1099 height: self.height.min(rhs.height),
1100 }
1101 }
1102
1103 pub fn max(self, rhs: Self) -> Self {
1105 Self {
1106 width: self.width.max(rhs.width),
1107 height: self.height.max(rhs.height),
1108 }
1109 }
1110}