1use std::{
2 collections::HashMap,
3 ops::{Add, AddAssign},
4 sync::Arc,
5};
6
7use dashmap::DashMap;
8use indextree::NodeId;
9use rayon::prelude::*;
10use rustc_hash::FxBuildHasher;
11use tracing::debug;
12use winit::window::CursorIcon;
13
14use crate::{
15 Px,
16 accessibility::{AccessibilityActionHandler, AccessibilityNode},
17 cursor::{CursorEventContent, PointerChange},
18 focus::{
19 FocusDirection, FocusRegistration, FocusRequester, FocusRevealRequest, FocusState,
20 FocusTraversalPolicy,
21 },
22 layout::{
23 LayoutInput, LayoutOutput, LayoutPolicyDyn, LayoutResult, PlacementInput, RenderPolicyDyn,
24 },
25 modifier::{LayoutModifierChild, LayoutModifierInput, LayoutModifierNode, Modifier},
26 prop::CallbackWith,
27 px::{PxPosition, PxSize},
28 render_graph::RenderFragment,
29 runtime::{
30 RuntimePhase, push_current_component_instance_key,
31 push_current_node_with_instance_logic_id, push_phase,
32 },
33 time::Instant,
34};
35
36use super::{
37 LayoutContext, LayoutSnapshotEntry, LayoutSnapshotMap,
38 constraint::{Constraint, DimensionValue, ParentConstraint},
39};
40
41#[cfg(feature = "profiling")]
42use crate::profiler::{Phase as ProfilerPhase, ScopeGuard as ProfilerScopeGuard};
43
44pub(crate) struct ComponentNode {
47 pub(crate) fn_name: String,
49 pub(crate) instance_logic_id: u64,
51 pub(crate) instance_key: u64,
53 pub(crate) pointer_preview_handlers: Vec<Box<PointerInputHandlerFn>>,
55 pub(crate) pointer_handlers: Vec<Box<PointerInputHandlerFn>>,
57 pub(crate) pointer_final_handlers: Vec<Box<PointerInputHandlerFn>>,
59 pub(crate) keyboard_preview_handlers: Vec<Box<KeyboardInputHandlerFn>>,
61 pub(crate) keyboard_handlers: Vec<Box<KeyboardInputHandlerFn>>,
63 pub(crate) ime_preview_handlers: Vec<Box<ImeInputHandlerFn>>,
65 pub(crate) ime_handlers: Vec<Box<ImeInputHandlerFn>>,
67 pub(crate) focus_requester_binding: Option<FocusRequester>,
69 pub(crate) focus_registration: Option<FocusRegistration>,
71 pub(crate) focus_restorer_fallback: Option<FocusRequester>,
73 pub(crate) focus_traversal_policy: Option<FocusTraversalPolicy>,
76 pub(crate) focus_changed_handler: Option<FocusChangedHandler>,
78 pub(crate) focus_event_handler: Option<FocusEventHandler>,
80 pub(crate) focus_beyond_bounds_handler: Option<FocusBeyondBoundsHandler>,
82 pub(crate) focus_reveal_handler: Option<FocusRevealHandler>,
85 pub(crate) modifier: Modifier,
87 pub(crate) layout_policy: Box<dyn LayoutPolicyDyn>,
89 pub(crate) render_policy: Box<dyn RenderPolicyDyn>,
91 pub(crate) replay: Option<crate::prop::ComponentReplayData>,
93 pub(crate) props_unchanged_from_previous: bool,
95}
96
97pub(crate) struct ComponentNodeMetaData {
99 pub computed_data: Option<ComputedData>,
102 pub layout_cache_hit: bool,
104 pub placement_order: Option<u64>,
106 pub rel_position: Option<PxPosition>,
109 pub abs_position: Option<PxPosition>,
113 pub event_clip_rect: Option<crate::PxRect>,
116 pub(crate) fragment: RenderFragment,
121 pub clips_children: bool,
123 pub opacity: f32,
125 pub accessibility: Option<AccessibilityNode>,
127 pub accessibility_action_handler: Option<AccessibilityActionHandler>,
129}
130
131impl ComponentNodeMetaData {
132 pub fn none() -> Self {
134 Self {
135 computed_data: None,
136 layout_cache_hit: false,
137 placement_order: None,
138 rel_position: None,
139 abs_position: None,
140 event_clip_rect: None,
141 fragment: RenderFragment::default(),
142 clips_children: false,
143 opacity: 1.0,
144 accessibility: None,
145 accessibility_action_handler: None,
146 }
147 }
148
149 pub fn fragment_mut(&mut self) -> &mut RenderFragment {
151 &mut self.fragment
152 }
153
154 pub(crate) fn take_fragment(&mut self) -> RenderFragment {
156 std::mem::take(&mut self.fragment)
157 }
158}
159
160impl Default for ComponentNodeMetaData {
161 fn default() -> Self {
162 Self::none()
163 }
164}
165
166fn reset_frame_metadata(node_id: NodeId, component_node_metadatas: &ComponentNodeMetaDatas) {
167 let mut metadata = component_node_metadatas.entry(node_id).or_default();
168 metadata.computed_data = None;
169 metadata.layout_cache_hit = false;
170 metadata.placement_order = None;
171 metadata.rel_position = None;
172 metadata.abs_position = None;
173 metadata.event_clip_rect = None;
174 metadata.fragment = RenderFragment::default();
175 metadata.clips_children = false;
176 metadata.opacity = 1.0;
177}
178
179pub(crate) type ComponentNodeTree = indextree::Arena<ComponentNode>;
181pub(crate) type ComponentNodeMetaDatas = DashMap<NodeId, ComponentNodeMetaData, FxBuildHasher>;
183
184#[derive(Debug, Clone, PartialEq)]
186pub enum MeasurementError {
187 NodeNotFoundInTree,
189 NodeNotFoundInMeta,
192 MeasureFnFailed(String),
195 ChildMeasurementFailed(NodeId),
199}
200
201#[derive(Debug, Clone, Copy, PartialEq, Eq)]
203pub enum PointerEventPass {
204 Initial,
206 Main,
208 Final,
210}
211
212pub type PointerInputHandlerFn = dyn Fn(PointerInput) + Send + Sync;
214pub type KeyboardInputHandlerFn = dyn Fn(KeyboardInput) + Send + Sync;
216pub type ImeInputHandlerFn = dyn Fn(ImeInput) + Send + Sync;
218pub type FocusChangedHandler = CallbackWith<FocusState>;
220pub type FocusEventHandler = CallbackWith<FocusState>;
222pub type FocusBeyondBoundsHandler = CallbackWith<FocusDirection, bool>;
224pub type FocusRevealHandler = CallbackWith<FocusRevealRequest, bool>;
226
227pub struct PointerInput<'a> {
234 pub pass: PointerEventPass,
236 pub computed_data: ComputedData,
238 pub cursor_position_rel: Option<PxPosition>,
241 pub(crate) cursor_position_abs: &'a mut Option<PxPosition>,
243 pub pointer_changes: &'a mut Vec<PointerChange>,
245 pub key_modifiers: winit::keyboard::ModifiersState,
247 pub(crate) ime_request: &'a mut Option<ImeRequest>,
248 pub(crate) window_action: &'a mut Option<WindowAction>,
249}
250
251impl PointerInput<'_> {
252 pub fn consume_pointer_changes(&mut self) {
254 for change in self.pointer_changes.iter_mut() {
255 change.consume();
256 }
257 }
258
259 pub fn has_unconsumed_release(&self) -> bool {
261 self.pointer_changes.iter().any(|change| {
262 !change.is_consumed() && matches!(change.content, CursorEventContent::Released(_))
263 })
264 }
265
266 pub fn block_cursor(&mut self) {
268 self.cursor_position_abs.take();
269 self.consume_pointer_changes();
270 }
271
272 pub fn block_all(&mut self) {
274 self.block_cursor();
275 }
276
277 fn set_window_action(&mut self, action: WindowAction) {
278 *self.window_action = Some(action);
279 }
280
281 pub fn drag_window(&mut self) {
283 self.set_window_action(WindowAction::DragWindow);
284 }
285
286 pub fn minimize_window(&mut self) {
288 self.set_window_action(WindowAction::Minimize);
289 }
290
291 pub fn maximize_window(&mut self) {
293 self.set_window_action(WindowAction::Maximize);
294 }
295
296 pub fn toggle_maximize_window(&mut self) {
298 self.set_window_action(WindowAction::ToggleMaximize);
299 }
300
301 pub fn close_window(&mut self) {
303 self.set_window_action(WindowAction::Close);
304 }
305
306 pub fn ime_session(&mut self) -> ImeSession<'_> {
308 ImeSession {
309 request: self.ime_request,
310 }
311 }
312}
313
314pub struct KeyboardInput<'a> {
320 pub computed_data: ComputedData,
322 pub keyboard_events: &'a mut Vec<winit::event::KeyEvent>,
324 pub key_modifiers: winit::keyboard::ModifiersState,
326 pub(crate) ime_request: &'a mut Option<ImeRequest>,
327}
328
329impl KeyboardInput<'_> {
330 pub fn block_keyboard(&mut self) {
332 self.keyboard_events.clear();
333 }
334
335 pub fn ime_session(&mut self) -> ImeSession<'_> {
337 ImeSession {
338 request: self.ime_request,
339 }
340 }
341}
342
343pub struct ImeInput<'a> {
348 pub computed_data: ComputedData,
350 pub ime_events: &'a mut Vec<winit::event::Ime>,
352 pub(crate) ime_request: &'a mut Option<ImeRequest>,
353}
354
355impl ImeInput<'_> {
356 pub fn block_ime(&mut self) {
358 self.ime_events.clear();
359 }
360
361 pub fn ime_session(&mut self) -> ImeSession<'_> {
363 ImeSession {
364 request: self.ime_request,
365 }
366 }
367}
368
369#[derive(Default, Debug)]
373pub(crate) struct WindowRequests {
374 pub cursor_icon: CursorIcon,
378 pub ime_request: Option<ImeRequest>,
383 pub window_action: Option<WindowAction>,
385}
386
387#[derive(Debug, Clone, Copy, PartialEq, Eq)]
389pub enum WindowAction {
390 DragWindow,
392 Minimize,
394 Maximize,
396 ToggleMaximize,
398 Close,
400}
401
402pub struct ImeSession<'a> {
408 request: &'a mut Option<ImeRequest>,
409}
410
411impl ImeSession<'_> {
412 pub fn update(&mut self, request: ImeRequest) {
414 *self.request = Some(request);
415 }
416
417 pub fn clear(&mut self) {
419 *self.request = None;
420 }
421}
422
423#[derive(Clone, Debug, PartialEq, Eq)]
426pub struct ImeRequest {
427 pub size: PxSize,
429 pub local_position: PxPosition,
431 pub selection_range: Option<std::ops::Range<usize>>,
433 pub composition_range: Option<std::ops::Range<usize>>,
435 pub(crate) position: Option<PxPosition>, }
439
440impl ImeRequest {
441 pub fn new(size: PxSize) -> Self {
445 Self {
446 size,
447 local_position: PxPosition::ZERO,
448 selection_range: None,
449 composition_range: None,
450 position: None, }
452 }
453
454 pub fn with_local_position(mut self, local_position: PxPosition) -> Self {
456 self.local_position = local_position;
457 self
458 }
459
460 pub fn with_selection_range(mut self, selection_range: Option<std::ops::Range<usize>>) -> Self {
462 self.selection_range = selection_range;
463 self
464 }
465
466 pub fn with_composition_range(
468 mut self,
469 composition_range: Option<std::ops::Range<usize>>,
470 ) -> Self {
471 self.composition_range = composition_range;
472 self
473 }
474}
475
476fn apply_layout_placements(
477 placements: &[(u64, PxPosition)],
478 tree: &ComponentNodeTree,
479 children: &[NodeId],
480 component_node_metadatas: &ComponentNodeMetaDatas,
481) {
482 if placements.is_empty() || children.is_empty() {
483 return;
484 }
485 let mut child_map = HashMap::new();
486 for child_id in children {
487 if let Some(child) = tree.get(*child_id) {
488 child_map.insert(child.get().instance_key, *child_id);
489 }
490 }
491 for (placement_order, (instance_key, position)) in placements.iter().enumerate() {
492 if let Some(child_id) = child_map.get(instance_key) {
493 place_node(
494 *child_id,
495 *position,
496 placement_order as u64,
497 component_node_metadatas,
498 );
499 }
500 }
501}
502
503fn restore_cached_subtree_metadata(
504 node_id: NodeId,
505 rel_position: Option<PxPosition>,
506 tree: &ComponentNodeTree,
507 component_node_metadatas: &ComponentNodeMetaDatas,
508 snapshots: &LayoutSnapshotMap,
509) -> bool {
510 let Some(node) = tree.get(node_id) else {
511 return false;
512 };
513 let instance_key = node.get().instance_key;
514 let Some(entry) = snapshots.get(&instance_key) else {
515 return false;
516 };
517
518 let size = entry.layout_result.size;
519 let placements = entry.layout_result.placements.clone();
520 drop(entry);
521
522 {
523 let mut metadata = component_node_metadatas.entry(node_id).or_default();
524 metadata.computed_data = Some(size);
525 metadata.layout_cache_hit = true;
526 if let Some(position) = rel_position {
527 metadata.rel_position = Some(position);
528 }
529 }
530
531 let mut child_positions = HashMap::new();
532 let mut child_orders = HashMap::new();
533 for (placement_order, (child_key, child_pos)) in placements.into_iter().enumerate() {
534 child_positions.insert(child_key, child_pos);
535 child_orders.insert(child_key, placement_order as u64);
536 }
537
538 for child_id in node_id.children(tree) {
539 let child_layout = tree.get(child_id).map(|child| {
540 let instance_key = child.get().instance_key;
541 (
542 child_positions.get(&instance_key).copied(),
543 child_orders.get(&instance_key).copied(),
544 )
545 });
546 let (child_rel_position, child_placement_order) = child_layout.unwrap_or((None, None));
547 if let Some(placement_order) = child_placement_order {
548 component_node_metadatas
549 .entry(child_id)
550 .or_default()
551 .placement_order = Some(placement_order);
552 }
553 if !restore_cached_subtree_metadata(
554 child_id,
555 child_rel_position,
556 tree,
557 component_node_metadatas,
558 snapshots,
559 ) {
560 return false;
561 }
562 }
563
564 true
565}
566
567#[derive(Clone)]
568struct MeasuredNodeLayout {
569 size: ComputedData,
570 placements: Vec<(u64, PxPosition)>,
571 measured_children: HashMap<NodeId, crate::layout::ChildMeasure>,
572}
573
574struct MeasureLayoutContext<'a, 'ctx> {
575 tree: &'a ComponentNodeTree,
576 children: &'a [NodeId],
577 component_node_metadatas: &'a ComponentNodeMetaDatas,
578 layout_ctx: Option<&'a LayoutContext<'ctx>>,
579 resolve_instance_key: &'a dyn Fn(NodeId) -> u64,
580}
581
582fn measure_base_layout(
583 layout_policy: &dyn LayoutPolicyDyn,
584 layout_ctx: &MeasureLayoutContext<'_, '_>,
585 constraint: &Constraint,
586) -> Result<MeasuredNodeLayout, MeasurementError> {
587 let input = LayoutInput::new(
588 layout_ctx.tree,
589 ParentConstraint::new(constraint),
590 layout_ctx.children,
591 layout_ctx.component_node_metadatas,
592 layout_ctx.layout_ctx,
593 );
594 let mut output = LayoutOutput::new(layout_ctx.resolve_instance_key);
595 let size = layout_policy.measure_dyn(&input, &mut output)?;
596 Ok(MeasuredNodeLayout {
597 size,
598 placements: output.finish(),
599 measured_children: input.take_measured_children(),
600 })
601}
602
603fn measure_with_layout_modifiers(
604 modifiers: &[Arc<dyn LayoutModifierNode>],
605 layout_policy: &dyn LayoutPolicyDyn,
606 layout_ctx: &MeasureLayoutContext<'_, '_>,
607 constraint: &Constraint,
608) -> Result<MeasuredNodeLayout, MeasurementError> {
609 if modifiers.is_empty() {
610 return measure_base_layout(layout_policy, layout_ctx, constraint);
611 }
612
613 struct ModifierChildRunner<'a, 'b> {
614 next: &'b mut dyn FnMut(&Constraint) -> Result<MeasuredNodeLayout, MeasurementError>,
615 last: Option<MeasuredNodeLayout>,
616 _marker: std::marker::PhantomData<&'a ()>,
617 }
618
619 impl LayoutModifierChild for ModifierChildRunner<'_, '_> {
620 fn measure(&mut self, constraint: &Constraint) -> Result<ComputedData, MeasurementError> {
621 let measured = (self.next)(constraint)?;
622 let size = measured.size;
623 self.last = Some(measured);
624 Ok(size)
625 }
626
627 fn place(&mut self, position: PxPosition, output: &mut LayoutOutput<'_>) {
628 let measured = self
629 .last
630 .as_ref()
631 .expect("layout modifier child must be measured before placement");
632 for (instance_key, child_position) in &measured.placements {
633 output.place_instance_key(*instance_key, position + *child_position);
634 }
635 }
636 }
637
638 let head = &modifiers[0];
639 let tail = &modifiers[1..];
640 let mut next = |next_constraint: &Constraint| {
641 measure_with_layout_modifiers(tail, layout_policy, layout_ctx, next_constraint)
642 };
643 let input = LayoutInput::new(
644 layout_ctx.tree,
645 ParentConstraint::new(constraint),
646 layout_ctx.children,
647 layout_ctx.component_node_metadatas,
648 layout_ctx.layout_ctx,
649 );
650 let modifier_input = LayoutModifierInput {
651 layout_input: &input,
652 };
653 let mut output = LayoutOutput::new(layout_ctx.resolve_instance_key);
654 let mut child = ModifierChildRunner {
655 next: &mut next,
656 last: None,
657 _marker: std::marker::PhantomData,
658 };
659 let size = head.measure(&modifier_input, &mut child, &mut output)?.size;
660 if let Some(measured) = child.last.as_ref() {
661 input.extend_measured_children(measured.measured_children.clone());
662 }
663 Ok(MeasuredNodeLayout {
664 size,
665 placements: output.finish(),
666 measured_children: input.take_measured_children(),
667 })
668}
669
670fn relayout_base_layout(
671 layout_policy: &dyn LayoutPolicyDyn,
672 tree: &ComponentNodeTree,
673 children: &[NodeId],
674 cached_child_sizes: &[ComputedData],
675 constraint: &Constraint,
676 cached_size: ComputedData,
677 resolve_instance_key: &dyn Fn(NodeId) -> u64,
678) -> Option<Vec<(u64, PxPosition)>> {
679 if cached_child_sizes.len() != children.len() {
680 return None;
681 }
682
683 let child_sizes: HashMap<NodeId, ComputedData> = children
684 .iter()
685 .copied()
686 .zip(cached_child_sizes.iter().copied())
687 .collect();
688 let input = PlacementInput::new(
689 tree,
690 ParentConstraint::new(constraint),
691 children,
692 &child_sizes,
693 cached_size,
694 );
695 let mut output = LayoutOutput::new(resolve_instance_key);
696 if !layout_policy.place_children_dyn(&input, &mut output) {
697 return None;
698 }
699 Some(output.finish())
700}
701
702pub(crate) fn measure_node(
708 node_id: NodeId,
709 parent_constraint: &Constraint,
710 tree: &ComponentNodeTree,
711 component_node_metadatas: &ComponentNodeMetaDatas,
712 layout_ctx: Option<&LayoutContext<'_>>,
713) -> Result<ComputedData, MeasurementError> {
714 let node_data_ref = tree
715 .get(node_id)
716 .ok_or(MeasurementError::NodeNotFoundInTree)?;
717 let node_data = node_data_ref.get();
718 #[cfg(feature = "profiling")]
719 let mut profiler_guard = Some(ProfilerScopeGuard::new(
720 ProfilerPhase::Measure,
721 Some(node_id),
722 node_data_ref.parent(),
723 Some(node_data.fn_name.as_str()),
724 ));
725
726 let children: Vec<_> = node_id.children(tree).collect(); let timer = Instant::now();
728
729 debug!(
730 "Measuring node {} with {} children, parent constraint: {:?}",
731 node_data.fn_name,
732 children.len(),
733 parent_constraint
734 );
735
736 let _node_ctx_guard = push_current_node_with_instance_logic_id(
739 node_id,
740 node_data.instance_logic_id,
741 node_data.fn_name.as_str(),
742 );
743 let _instance_ctx_guard = push_current_component_instance_key(node_data.instance_key);
744 let _phase_guard = push_phase(RuntimePhase::Measure);
745
746 let resolve_instance_key = |child_id: NodeId| {
747 if let Some(child) = tree.get(child_id) {
748 child.get().instance_key
749 } else {
750 debug_assert!(
751 false,
752 "Child node must exist when resolving layout placements"
753 );
754 0
755 }
756 };
757 let layout_policy = &node_data.layout_policy;
758 let layout_modifiers = node_data.modifier.layout_nodes();
759 if let Some(layout_ctx) = layout_ctx {
760 layout_ctx.diagnostics.inc_measure_node_calls();
761 if let Some(entry) = layout_ctx.snapshots.get(&node_data.instance_key) {
762 let same_constraint = entry.constraint_key == *parent_constraint;
763 let node_self_measure_dirty = layout_ctx
764 .measure_self_nodes
765 .contains(&node_data.instance_key);
766 let node_self_placement_dirty = layout_ctx
767 .placement_self_nodes
768 .contains(&node_data.instance_key);
769 let node_effective_dirty = layout_ctx
770 .dirty_effective_nodes
771 .contains(&node_data.instance_key);
772 let has_all_child_constraints = entry.child_constraints.len() == children.len();
773 let has_all_child_sizes = entry.child_sizes.len() == children.len();
774 let can_try_reuse = same_constraint
775 && !node_self_measure_dirty
776 && has_all_child_constraints
777 && (!node_effective_dirty || has_all_child_sizes);
778 if can_try_reuse {
779 let cached_result = entry.layout_result.clone();
780 let cached_child_constraints = entry.child_constraints.clone();
781 let cached_child_sizes = entry.child_sizes.clone();
782 drop(entry);
783
784 if !node_effective_dirty
785 && restore_cached_subtree_metadata(
786 node_id,
787 None,
788 tree,
789 component_node_metadatas,
790 layout_ctx.snapshots,
791 )
792 {
793 apply_layout_placements(
794 &cached_result.placements,
795 tree,
796 &children,
797 component_node_metadatas,
798 );
799 layout_ctx.diagnostics.inc_cache_hit_direct();
800 return Ok(cached_result.size);
801 }
802
803 let dirty_children: Vec<(usize, NodeId, Constraint)> = children
804 .iter()
805 .enumerate()
806 .filter_map(|(index, child_id)| {
807 tree.get(*child_id).and_then(|child| {
808 if layout_ctx
809 .dirty_effective_nodes
810 .contains(&child.get().instance_key)
811 {
812 Some((index, *child_id, cached_child_constraints[index]))
813 } else {
814 None
815 }
816 })
817 })
818 .collect();
819
820 let nodes_to_measure = dirty_children
821 .iter()
822 .map(|(_, child_id, constraint)| (*child_id, *constraint))
823 .collect();
824 let measured = measure_nodes(
825 nodes_to_measure,
826 tree,
827 component_node_metadatas,
828 Some(layout_ctx),
829 );
830 let mut child_size_changed = false;
831 for (index, child_id, _constraint) in &dirty_children {
832 let Some(result) = measured.get(child_id) else {
833 layout_ctx.diagnostics.inc_cache_miss_no_entry();
834 return Err(MeasurementError::NodeNotFoundInTree);
835 };
836 match result {
837 Ok(size) => {
838 if *size != cached_child_sizes[*index] {
839 child_size_changed = true;
840 break;
841 }
842 }
843 Err(err) => return Err(err.clone()),
844 }
845 }
846 if child_size_changed {
847 layout_ctx.diagnostics.inc_cache_miss_child_size();
848 } else {
849 let mut restored = true;
850 for child_id in &children {
851 let Some(child) = tree.get(*child_id) else {
852 restored = false;
853 break;
854 };
855 if layout_ctx
856 .dirty_effective_nodes
857 .contains(&child.get().instance_key)
858 {
859 continue;
860 }
861 if !restore_cached_subtree_metadata(
862 *child_id,
863 None,
864 tree,
865 component_node_metadatas,
866 layout_ctx.snapshots,
867 ) {
868 restored = false;
869 break;
870 }
871 }
872 if restored {
873 reset_frame_metadata(node_id, component_node_metadatas);
874 let placements = if node_self_placement_dirty {
875 match relayout_base_layout(
876 layout_policy.as_ref(),
877 tree,
878 &children,
879 &cached_child_sizes,
880 parent_constraint,
881 cached_result.size,
882 &resolve_instance_key,
883 ) {
884 Some(placements) => placements,
885 None => {
886 layout_ctx.diagnostics.inc_cache_miss_dirty_self();
887 Vec::new()
890 }
891 }
892 } else {
893 cached_result.placements.clone()
894 };
895 if node_self_placement_dirty && placements.is_empty() {
896 } else {
898 apply_layout_placements(
899 &placements,
900 tree,
901 &children,
902 component_node_metadatas,
903 );
904 if let Some(mut metadata) = component_node_metadatas.get_mut(&node_id) {
905 metadata.computed_data = Some(cached_result.size);
906 metadata.layout_cache_hit = true;
907 }
908 if node_self_placement_dirty {
909 layout_ctx.snapshots.insert(
910 node_data.instance_key,
911 LayoutSnapshotEntry {
912 constraint_key: *parent_constraint,
913 layout_result: LayoutResult {
914 size: cached_result.size,
915 placements,
916 },
917 child_constraints: cached_child_constraints,
918 child_sizes: cached_child_sizes,
919 },
920 );
921 }
922 layout_ctx.diagnostics.inc_cache_hit_boundary();
923 return Ok(cached_result.size);
924 }
925 }
926 }
927 }
928 if !same_constraint {
929 layout_ctx.diagnostics.inc_cache_miss_constraint();
930 } else if node_self_measure_dirty || node_self_placement_dirty {
931 layout_ctx.diagnostics.inc_cache_miss_dirty_self();
932 } else if node_effective_dirty {
933 layout_ctx.diagnostics.inc_cache_miss_child_size();
934 } else {
935 layout_ctx.diagnostics.inc_cache_miss_no_entry();
936 }
937 } else {
938 layout_ctx.diagnostics.inc_cache_miss_no_entry();
939 }
940 }
941
942 reset_frame_metadata(node_id, component_node_metadatas);
943 let measure_layout_ctx = MeasureLayoutContext {
944 tree,
945 children: &children,
946 component_node_metadatas,
947 layout_ctx,
948 resolve_instance_key: &resolve_instance_key,
949 };
950 let measured = measure_with_layout_modifiers(
951 &layout_modifiers,
952 layout_policy.as_ref(),
953 &measure_layout_ctx,
954 parent_constraint,
955 )?;
956 let size = measured.size;
957 let measured_children = measured.measured_children;
958 let placements = measured.placements;
959 apply_layout_placements(&placements, tree, &children, component_node_metadatas);
960
961 component_node_metadatas
962 .entry(node_id)
963 .or_default()
964 .computed_data = Some(size);
965
966 #[cfg(feature = "profiling")]
967 if let Some(guard) = &mut profiler_guard {
968 guard.set_computed_size(size.width.0, size.height.0);
969 }
970
971 if let Some(layout_ctx) = layout_ctx {
972 let mut cacheable = true;
973 let mut child_constraints = Vec::with_capacity(children.len());
974 let mut child_sizes = Vec::with_capacity(children.len());
975 for child_id in &children {
976 let Some(measurement) = measured_children.get(child_id) else {
977 cacheable = false;
978 break;
979 };
980 if !measurement.consistent {
981 cacheable = false;
982 break;
983 }
984 child_constraints.push(measurement.constraint);
985 child_sizes.push(measurement.size);
986 }
987 if cacheable {
988 let layout_result = LayoutResult { size, placements };
989 layout_ctx.snapshots.insert(
990 node_data.instance_key,
991 LayoutSnapshotEntry {
992 constraint_key: *parent_constraint,
993 layout_result,
994 child_constraints,
995 child_sizes,
996 },
997 );
998 layout_ctx.diagnostics.inc_cache_store_count();
999 } else {
1000 layout_ctx.snapshots.remove(&node_data.instance_key);
1001 layout_ctx.diagnostics.inc_cache_drop_non_cacheable_count();
1002 }
1003 }
1004
1005 debug!(
1006 "Measured node {} in {:?} with size {:?}",
1007 node_data.fn_name,
1008 timer.elapsed(),
1009 size
1010 );
1011
1012 #[cfg(feature = "profiling")]
1013 if let Some(guard) = &mut profiler_guard {
1014 guard.set_computed_size(size.width.0, size.height.0);
1015 }
1016
1017 Ok(size)
1018}
1019
1020pub(crate) fn place_node(
1022 node: indextree::NodeId,
1023 rel_position: PxPosition,
1024 placement_order: u64,
1025 component_node_metadatas: &ComponentNodeMetaDatas,
1026) {
1027 let mut metadata = component_node_metadatas.entry(node).or_default();
1028 metadata.rel_position = Some(rel_position);
1029 metadata.placement_order = Some(placement_order);
1030}
1031
1032pub(crate) fn measure_nodes(
1034 nodes_to_measure: Vec<(NodeId, Constraint)>,
1035 tree: &ComponentNodeTree,
1036 component_node_metadatas: &ComponentNodeMetaDatas,
1037 layout_ctx: Option<&LayoutContext<'_>>,
1038) -> HashMap<NodeId, Result<ComputedData, MeasurementError>> {
1039 if nodes_to_measure.is_empty() {
1040 return HashMap::new();
1041 }
1042 for (node_id, _) in &nodes_to_measure {
1044 reset_frame_metadata(*node_id, component_node_metadatas);
1045 }
1046 nodes_to_measure
1047 .into_par_iter()
1048 .map(|(node_id, parent_constraint)| {
1049 let result = measure_node(
1050 node_id,
1051 &parent_constraint,
1052 tree,
1053 component_node_metadatas,
1054 layout_ctx,
1055 );
1056 (node_id, result)
1057 })
1058 .collect::<HashMap<NodeId, Result<ComputedData, MeasurementError>>>()
1059}
1060
1061#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1064pub struct ComputedData {
1065 pub width: Px,
1067 pub height: Px,
1069}
1070
1071impl Add for ComputedData {
1072 type Output = Self;
1073 fn add(self, rhs: Self) -> Self::Output {
1074 Self {
1075 width: self.width + rhs.width,
1076 height: self.height + rhs.height,
1077 }
1078 }
1079}
1080
1081impl AddAssign for ComputedData {
1082 fn add_assign(&mut self, rhs: Self) {
1083 *self = *self + rhs;
1084 }
1085}
1086
1087impl ComputedData {
1088 pub const ZERO: Self = Self {
1090 width: Px(0),
1091 height: Px(0),
1092 };
1093
1094 pub fn min_from_constraint(constraint: &Constraint) -> Self {
1098 let width = match constraint.width {
1099 DimensionValue::Fixed(w) => w,
1100 DimensionValue::Wrap { min, .. } => min.unwrap_or(Px(0)),
1101 DimensionValue::Fill { min, .. } => min.unwrap_or(Px(0)),
1102 };
1103 let height = match constraint.height {
1104 DimensionValue::Fixed(h) => h,
1105 DimensionValue::Wrap { min, .. } => min.unwrap_or(Px(0)),
1106 DimensionValue::Fill { min, .. } => min.unwrap_or(Px(0)),
1107 };
1108 Self { width, height }
1109 }
1110
1111 pub fn min(self, rhs: Self) -> Self {
1113 Self {
1114 width: self.width.min(rhs.width),
1115 height: self.height.min(rhs.height),
1116 }
1117 }
1118
1119 pub fn max(self, rhs: Self) -> Self {
1121 Self {
1122 width: self.width.max(rhs.width),
1123 height: self.height.max(rhs.height),
1124 }
1125 }
1126}