1use std::{
2 collections::HashMap,
3 num::NonZeroUsize,
4 ops::{Add, AddAssign, Deref},
5 sync::Arc,
6};
7
8use indextree::NodeId;
9use smallvec::SmallVec;
10use tracing::debug;
11use winit::window::CursorIcon;
12
13use crate::{
14 ClipRegion, Px,
15 accessibility::{AccessibilityActionHandler, AccessibilityNode, StoredSemantics},
16 cursor::{CursorEventContent, PointerChange},
17 focus::{
18 FocusDirection, FocusRegistration, FocusRequester, FocusRevealRequest, FocusState,
19 FocusTraversalPolicy,
20 },
21 layout::{
22 ChildMeasure, DefaultLayoutNode, LayoutInput, LayoutModifierDyn, LayoutModifierHandle,
23 LayoutResult, NoopDrawModifier, PlacementResult, PlacementScope,
24 },
25 modifier::{
26 DrawModifierNode, LayoutModifierChild, LayoutModifierInput, LayoutModifierNode, Modifier,
27 },
28 prop::CallbackWith,
29 px::{PxPosition, PxRect, PxSize},
30 render_graph::RenderFragment,
31 runtime::{
32 RuntimePhase, push_current_component_instance_key,
33 push_current_node_with_instance_logic_id, push_measured_node_instance_key, push_phase,
34 },
35 time::Instant,
36};
37
38use super::{
39 DrawLayoutBounds, LayoutContext, LayoutSnapshotEntry, NodeDrawLayout,
40 constraint::{Constraint, ParentConstraint},
41 nearest_replay_boundary_instance_key,
42 node_map::DenseNodeMap,
43};
44
45#[cfg(feature = "profiling")]
46use crate::profiler::{Phase as ProfilerPhase, ScopeGuard as ProfilerScopeGuard};
47
48#[derive(Clone, Copy, Debug, Eq, PartialEq)]
51pub(crate) enum NodeRole {
52 Composition,
53 Layout,
54}
55
56pub(crate) struct ComponentNode {
57 pub(crate) fn_name: &'static str,
59 pub(crate) role: NodeRole,
62 pub(super) layout_children: Option<LayoutChildren>,
63 pub(super) layout_children_dirty: bool,
64 pub(crate) sibling_index: Option<NonZeroUsize>,
65 #[cfg(feature = "profiling")]
66 pub(crate) subtree_len: usize,
67 pub(crate) children_scale: f32,
68 pub(crate) instance_logic_id: u64,
70 pub(crate) instance_key: u64,
72 pub(crate) interaction: Option<Box<NodeInteraction>>,
73 pub(crate) layout_coordinate_space: bool,
74 pub(crate) modifier: Modifier,
76 pub(crate) layout_node: Box<dyn LayoutModifierDyn>,
78 pub(crate) layout_input_policy: LayoutModifierHandle,
79 pub(crate) draw_node: Box<dyn DrawModifierNode>,
81 pub(crate) replay_boundary: bool,
82 pub(crate) props_unchanged_from_previous: bool,
84}
85
86impl ComponentNode {
87 pub(crate) fn new(fn_name: &'static str, role: NodeRole) -> Self {
88 Self {
89 fn_name,
90 role,
91 layout_children: None,
92 layout_children_dirty: true,
93 sibling_index: None,
94 #[cfg(feature = "profiling")]
95 subtree_len: 1,
96 children_scale: 1.0,
97 instance_logic_id: 0,
98 instance_key: 0,
99 interaction: None,
100 layout_coordinate_space: false,
101 modifier: Modifier::default(),
102 layout_node: Box::new(DefaultLayoutNode),
103 layout_input_policy: LayoutModifierHandle::default(),
104 draw_node: Box::new(NoopDrawModifier),
105 replay_boundary: false,
106 props_unchanged_from_previous: false,
107 }
108 }
109
110 pub(crate) fn interaction(&self) -> &NodeInteraction {
111 static EMPTY: NodeInteraction = NodeInteraction::EMPTY;
112 self.interaction.as_deref().unwrap_or(&EMPTY)
113 }
114
115 pub(crate) fn layout_policy(&self) -> &dyn LayoutModifierDyn {
116 self.layout_input_policy.as_policy()
117 }
118
119 pub(crate) fn interaction_mut(&mut self) -> &mut NodeInteraction {
120 self.interaction
121 .get_or_insert_with(|| Box::new(NodeInteraction::EMPTY))
122 }
123}
124
125pub(crate) struct NodeInteraction {
126 pub(crate) pointer_preview_handlers: Vec<Box<PointerInputHandlerFn>>,
128 pub(crate) pointer_handlers: Vec<Box<PointerInputHandlerFn>>,
130 pub(crate) pointer_final_handlers: Vec<Box<PointerInputHandlerFn>>,
132 pub(crate) keyboard_preview_handlers: Vec<Box<KeyboardInputHandlerFn>>,
134 pub(crate) keyboard_handlers: Vec<Box<KeyboardInputHandlerFn>>,
136 pub(crate) ime_preview_handlers: Vec<Box<ImeInputHandlerFn>>,
138 pub(crate) ime_handlers: Vec<Box<ImeInputHandlerFn>>,
140 pub(crate) focus_requester_binding: Option<FocusRequester>,
142 pub(crate) focus_registration: Option<FocusRegistration>,
144 pub(crate) focus_restorer_fallback: Option<FocusRequester>,
146 pub(crate) focus_traversal_policy: Option<FocusTraversalPolicy>,
149 pub(crate) focus_changed_handler: Option<FocusChangedHandler>,
151 pub(crate) focus_event_handler: Option<FocusEventHandler>,
153 pub(crate) focus_beyond_bounds_handler: Option<FocusBeyondBoundsHandler>,
155 pub(crate) focus_reveal_handler: Option<FocusRevealHandler>,
158 pub(crate) globally_positioned_handlers: Vec<GloballyPositionedHandler>,
160}
161
162impl NodeInteraction {
163 const EMPTY: Self = Self {
164 pointer_preview_handlers: Vec::new(),
165 pointer_handlers: Vec::new(),
166 pointer_final_handlers: Vec::new(),
167 keyboard_preview_handlers: Vec::new(),
168 keyboard_handlers: Vec::new(),
169 ime_preview_handlers: Vec::new(),
170 ime_handlers: Vec::new(),
171 focus_requester_binding: None,
172 focus_registration: None,
173 focus_restorer_fallback: None,
174 focus_traversal_policy: None,
175 focus_changed_handler: None,
176 focus_event_handler: None,
177 focus_beyond_bounds_handler: None,
178 focus_reveal_handler: None,
179 globally_positioned_handlers: Vec::new(),
180 };
181
182 pub(super) fn has_pointer_handlers(&self) -> bool {
183 !self.pointer_preview_handlers.is_empty()
184 || !self.pointer_handlers.is_empty()
185 || !self.pointer_final_handlers.is_empty()
186 }
187
188 pub(super) fn observes_input_geometry(&self) -> bool {
189 self.has_pointer_handlers()
190 || !self.keyboard_preview_handlers.is_empty()
191 || !self.keyboard_handlers.is_empty()
192 || !self.ime_preview_handlers.is_empty()
193 || !self.ime_handlers.is_empty()
194 || self.focus_registration.is_some()
195 }
196}
197
198#[derive(Clone)]
199pub(super) struct InputTransforms {
200 pub(super) parent: crate::LocalToWindow,
201 positions: Arc<[PxPosition]>,
202}
203
204impl InputTransforms {
205 pub(super) fn get(&self, index: usize) -> Option<crate::LocalToWindow> {
206 self.positions
207 .get(index)
208 .map(|position| self.parent.with_local_origin(*position))
209 }
210}
211
212pub(crate) struct ComponentNodeMetaData {
214 pub(super) prepared_layout: Option<super::PreparedLayoutMetadata>,
215 pub(super) clip_regions: Option<Box<ClipRegions>>,
216 pub(super) geometry_initialized: bool,
217 pub(super) observes_geometry: bool,
218 pub(super) observes_size: bool,
219 pub(super) paint_dirty: bool,
220 accessibility_written: bool,
221 pub computed_data: Option<ComputedData>,
224 pub draw_layout: NodeDrawLayout,
225 pub layout_cache_hit: bool,
227 pub placement_order: Option<u64>,
229 pub rel_position: Option<PxPosition>,
232 pub base_abs_position: Option<PxPosition>,
237 pub local_to_window: Option<crate::LocalToWindow>,
238 pub(super) input_transforms: Option<Box<InputTransforms>>,
239 pub event_clip_bounds: Option<crate::FloatRect>,
240 pub abs_position: Option<PxPosition>,
245 pub(crate) fragment: RenderFragment,
250 pub clips_children: bool,
252 pub(crate) has_shape_clipping: bool,
253 pub opacity: f32,
255 pub accessibility: Option<StoredSemantics>,
257 pub accessibility_action_handler: Option<AccessibilityActionHandler>,
259}
260
261#[derive(Default)]
262pub(super) struct ClipRegions {
263 local: Option<ClipRegion>,
264 prepared: Option<ClipRegion>,
265}
266
267impl ComponentNodeMetaData {
268 pub fn none() -> Self {
270 Self {
271 prepared_layout: None,
272 clip_regions: None,
273 geometry_initialized: false,
274 observes_geometry: false,
275 observes_size: false,
276 paint_dirty: true,
277 accessibility_written: false,
278 computed_data: None,
279 draw_layout: NodeDrawLayout::default(),
280 layout_cache_hit: false,
281 placement_order: None,
282 rel_position: None,
283 base_abs_position: None,
284 local_to_window: None,
285 input_transforms: None,
286 event_clip_bounds: None,
287 abs_position: None,
288 fragment: RenderFragment::default(),
289 clips_children: false,
290 has_shape_clipping: false,
291 opacity: 1.0,
292 accessibility: None,
293 accessibility_action_handler: None,
294 }
295 }
296
297 pub(crate) fn set_accessibility(
298 &mut self,
299 node: Option<AccessibilityNode>,
300 handler: Option<AccessibilityActionHandler>,
301 ) {
302 if let Some(node) = node {
303 StoredSemantics::write(&mut self.accessibility, node);
304 } else {
305 self.accessibility = None;
306 }
307 self.accessibility_action_handler = handler;
308 self.accessibility_written = true;
309 }
310
311 pub(super) fn begin_accessibility_rebuild(&mut self) {
312 self.accessibility_written = false;
313 self.accessibility_action_handler = None;
314 }
315
316 pub(super) fn finish_accessibility_rebuild(&mut self) {
317 if !self.accessibility_written {
318 self.accessibility = None;
319 }
320 }
321
322 pub fn fragment_mut(&mut self) -> &mut RenderFragment {
324 &mut self.fragment
325 }
326
327 pub(crate) fn event_clip_rect(&self) -> Option<PxRect> {
328 self.event_clip_bounds.map(crate::FloatRect::outward)
329 }
330
331 pub(super) fn set_input_transforms(
332 &mut self,
333 parent: crate::LocalToWindow,
334 positions: Vec<PxPosition>,
335 ) {
336 if positions.is_empty() {
337 self.input_transforms = None;
338 } else if let Some(transforms) = &mut self.input_transforms {
339 transforms.parent = parent;
340 if transforms.positions.as_ref() != positions.as_slice() {
341 transforms.positions = positions.into();
342 }
343 } else {
344 self.input_transforms = Some(Box::new(InputTransforms {
345 parent,
346 positions: positions.into(),
347 }));
348 }
349 }
350
351 pub(crate) fn clip_region(&self) -> Option<&ClipRegion> {
352 self.clip_regions.as_ref()?.local.as_ref()
353 }
354
355 pub(crate) fn set_clip_region(&mut self, region: Option<ClipRegion>) {
356 if region.is_some() {
357 self.clip_regions.get_or_insert_with(Box::default).local = region;
358 } else if let Some(regions) = &mut self.clip_regions {
359 regions.local = None;
360 }
361 }
362
363 pub(super) fn prepared_clip_region(&self) -> Option<&ClipRegion> {
364 self.clip_regions.as_ref()?.prepared.as_ref()
365 }
366
367 pub(super) fn set_prepared_clip_region(&mut self, region: Option<ClipRegion>) {
368 if let Some(regions) = &mut self.clip_regions {
369 if regions.prepared != region {
370 regions.prepared = region;
371 }
372 if regions.local.is_none() && region.is_none() {
373 self.clip_regions = None;
374 }
375 }
376 }
377}
378
379impl Default for ComponentNodeMetaData {
380 fn default() -> Self {
381 Self::none()
382 }
383}
384
385pub(crate) fn sibling_index(id: NodeId, tree: &ComponentNodeTree) -> usize {
386 tree[id].get().sibling_index.map_or_else(
387 || id.preceding_siblings(tree).skip(1).count(),
388 |index| index.get() - 1,
389 )
390}
391
392#[derive(Clone)]
393pub(crate) enum LayoutChildren {
394 Empty,
395 One(NodeId),
396 Shared(Arc<[NodeId]>),
397}
398
399impl LayoutChildren {
400 pub(super) fn new(children: &[NodeId]) -> Self {
401 match children {
402 [] => Self::Empty,
403 [child] => Self::One(*child),
404 _ => Self::Shared(children.into()),
405 }
406 }
407}
408
409impl AsRef<[NodeId]> for LayoutChildren {
410 fn as_ref(&self) -> &[NodeId] {
411 self
412 }
413}
414
415impl Deref for LayoutChildren {
416 type Target = [NodeId];
417
418 fn deref(&self) -> &[NodeId] {
419 match self {
420 Self::Empty => &[],
421 Self::One(child) => std::slice::from_ref(child),
422 Self::Shared(children) => children,
423 }
424 }
425}
426
427pub(crate) fn direct_layout_children(node_id: NodeId, tree: &ComponentNodeTree) -> LayoutChildren {
428 if let Some(children) = tree
429 .get(node_id)
430 .and_then(|node| node.get().layout_children.as_ref())
431 {
432 return children.clone();
433 }
434 fn collect(node_id: NodeId, tree: &ComponentNodeTree, output: &mut SmallVec<[NodeId; 4]>) {
435 let Some(node_ref) = tree.get(node_id) else {
436 return;
437 };
438 if node_ref.get().role == NodeRole::Layout {
439 output.push(node_id);
440 return;
441 }
442
443 for child_id in node_id.children(tree) {
444 collect(child_id, tree, output);
445 }
446 }
447
448 let mut children = SmallVec::new();
449 for child_id in node_id.children(tree) {
450 collect(child_id, tree, &mut children);
451 }
452 LayoutChildren::new(&children)
453}
454
455fn reset_frame_metadata(
456 node_id: NodeId,
457 component_node_metadatas: &mut ComponentNodeMetaDatas,
458) -> Option<ComputedData> {
459 component_node_metadatas.mark_paint_dirty(node_id);
460 let metadata = component_node_metadatas.entry_or_default(node_id);
461 metadata.draw_layout = NodeDrawLayout::default();
462 metadata.layout_cache_hit = false;
463 metadata.paint_dirty = true;
464 metadata.computed_data.take()
465}
466
467pub(crate) type ComponentNodeTree = indextree::Arena<ComponentNode>;
469
470#[derive(Default)]
472pub(crate) struct ComponentNodeMetaDatas {
473 nodes: DenseNodeMap<ComponentNodeMetaData>,
474 #[cfg(feature = "profiling")]
475 pub(super) profiling_dirty: rustc_hash::FxHashSet<NodeId>,
476 pub(super) geometry_visits: u64,
477 pub(super) geometry_dirty: rustc_hash::FxHashSet<NodeId>,
478 pub(super) geometry_changed: rustc_hash::FxHashSet<NodeId>,
479 pub(super) size_changed: rustc_hash::FxHashSet<NodeId>,
480 pub(super) paint_changed: rustc_hash::FxHashSet<NodeId>,
481 pub(super) placement_order_dirty: rustc_hash::FxHashSet<NodeId>,
482 pub(crate) placement_order_changed: rustc_hash::FxHashSet<NodeId>,
483 pub(super) paint_dirty_nodes: rustc_hash::FxHashSet<NodeId>,
484}
485
486impl ComponentNodeMetaDatas {
487 pub(crate) fn new() -> Self {
488 Self::default()
489 }
490
491 pub(crate) fn clear(&mut self) {
492 self.nodes.clear();
493 #[cfg(feature = "profiling")]
494 self.profiling_dirty.clear();
495 self.geometry_dirty.clear();
496 self.geometry_changed.clear();
497 self.size_changed.clear();
498 self.paint_dirty_nodes.clear();
499 self.paint_changed.clear();
500 self.placement_order_dirty.clear();
501 self.placement_order_changed.clear();
502 }
503
504 pub(crate) fn remove(&mut self, node_id: &NodeId) -> Option<ComponentNodeMetaData> {
505 #[cfg(feature = "profiling")]
506 self.profiling_dirty.remove(node_id);
507 self.geometry_dirty.remove(node_id);
508 self.geometry_changed.remove(node_id);
509 self.size_changed.remove(node_id);
510 self.paint_dirty_nodes.remove(node_id);
511 self.paint_changed.remove(node_id);
512 self.placement_order_dirty.remove(node_id);
513 self.placement_order_changed.remove(node_id);
514 self.nodes.remove(*node_id)
515 }
516
517 pub(crate) fn get(&self, node_id: &NodeId) -> Option<&ComponentNodeMetaData> {
518 self.nodes.get(*node_id)
519 }
520
521 pub(crate) fn get_mut(&mut self, node_id: &NodeId) -> Option<&mut ComponentNodeMetaData> {
522 self.nodes.get_mut(*node_id)
523 }
524
525 pub(crate) fn entry_or_default(&mut self, node_id: NodeId) -> &mut ComponentNodeMetaData {
526 if let Some(previous) = self.nodes.id_at_slot(node_id) {
527 if previous == node_id {
528 return self.nodes.get_mut(node_id).expect("occupied node slot");
529 }
530 self.remove(&previous);
531 }
532 self.geometry_dirty.insert(node_id);
533 self.paint_dirty_nodes.insert(node_id);
534 self.nodes.insert(node_id, ComponentNodeMetaData::default())
535 }
536
537 pub(crate) fn mark_geometry_dirty(&mut self, node_id: NodeId) {
538 self.geometry_dirty.insert(node_id);
539 }
540
541 pub(crate) fn mark_paint_dirty(&mut self, node_id: NodeId) {
542 self.paint_dirty_nodes.insert(node_id);
543 if let Some(metadata) = self.get_mut(&node_id) {
544 metadata.paint_dirty = true;
545 }
546 }
547}
548
549#[derive(Debug, Clone, PartialEq)]
551pub enum MeasurementError {
552 NodeNotFoundInTree,
554 NodeNotFoundInMeta,
557 MeasureFnFailed(String),
560 ChildMeasurementFailed(NodeId),
564}
565
566#[derive(Debug, Clone, Copy, PartialEq, Eq)]
568pub enum PointerEventPass {
569 Initial,
571 Main,
573 Final,
575}
576
577pub type PointerInputHandlerFn = dyn Fn(PointerInput) + Send + Sync;
579pub type KeyboardInputHandlerFn = dyn Fn(KeyboardInput) + Send + Sync;
581pub type ImeInputHandlerFn = dyn Fn(ImeInput) + Send + Sync;
583pub type FocusChangedHandler = CallbackWith<FocusState>;
585pub type FocusEventHandler = CallbackWith<FocusState>;
587pub type FocusBeyondBoundsHandler = CallbackWith<FocusDirection, bool>;
589pub type FocusRevealHandler = CallbackWith<FocusRevealRequest, bool>;
591#[derive(Clone, Copy, PartialEq)]
593pub enum GloballyPositionedHandler {
594 Pixels(CallbackWith<PxRect>),
595 Precise(CallbackWith<crate::FloatRect>),
596 Transform(CallbackWith<crate::LocalToWindow>),
597 Coordinates(CallbackWith<crate::LayoutCoordinates>),
598 Visible(CallbackWith<Option<crate::FloatRect>>),
601 InSpace(CallbackWith<crate::FloatRect>),
603 Size(CallbackWith<PxSize>),
605}
606
607#[derive(Clone, Copy)]
608pub(crate) struct GeometryObservation {
609 pub rounded: PxRect,
610 pub precise: crate::FloatRect,
611 pub transform: crate::LocalToWindow,
612 pub coordinates: crate::LayoutCoordinates,
613 pub in_space: crate::FloatRect,
614 pub visible: Option<crate::FloatRect>,
615}
616
617impl GloballyPositionedHandler {
618 pub(crate) fn changed(self, previous: GeometryObservation, next: GeometryObservation) -> bool {
619 match self {
620 Self::Pixels(_) => previous.rounded != next.rounded,
621 Self::Precise(_) => previous.precise != next.precise,
622 Self::Transform(_) => previous.transform != next.transform,
623 Self::Coordinates(_) => previous.coordinates != next.coordinates,
624 Self::Visible(_) => previous.visible != next.visible,
625 Self::InSpace(_) => previous.in_space != next.in_space,
626 Self::Size(_) => previous.coordinates.local_size != next.coordinates.local_size,
627 }
628 }
629
630 pub(crate) fn call(self, geometry: GeometryObservation) {
631 match self {
632 Self::Pixels(handler) => handler.call(geometry.rounded),
633 Self::Precise(handler) => handler.call(geometry.precise),
634 Self::Transform(handler) => handler.call(geometry.transform),
635 Self::Coordinates(handler) => handler.call(geometry.coordinates),
636 Self::Visible(handler) => handler.call(geometry.visible),
637 Self::InSpace(handler) => handler.call(geometry.in_space),
638 Self::Size(handler) => handler.call(geometry.coordinates.local_size),
639 }
640 }
641}
642
643pub struct PointerInput<'a> {
650 pub local_to_window: crate::LocalToWindow,
653 pub pass: PointerEventPass,
655 pub computed_data: ComputedData,
657 pub cursor_position_rel: Option<PxPosition>,
660 pub(crate) cursor_position_abs: &'a mut Option<PxPosition>,
662 pub pointer_changes: &'a mut Vec<PointerChange>,
664 pub key_modifiers: winit::keyboard::ModifiersState,
666 pub(crate) ime_request: &'a mut Option<ImeRequest>,
667 pub(crate) request_window_drag: &'a mut Option<WindowDragRequest>,
668}
669
670impl PointerInput<'_> {
671 pub fn local_delta(&self, dx: f32, dy: f32) -> (f32, f32) {
673 let delta = self
674 .local_to_window
675 .inverse_vector(PxPosition::from_f32_xy(dx, dy));
676 (delta.x, delta.y)
677 }
678
679 pub fn consume_pointer_changes(&mut self) {
681 for change in self.pointer_changes.iter_mut() {
682 if matches!(change.content, CursorEventContent::Scroll(_)) {
683 continue;
684 }
685 change.consume();
686 }
687 }
688
689 pub fn has_unconsumed_release(&self) -> bool {
691 self.pointer_changes.iter().any(|change| {
692 !change.is_consumed() && matches!(change.content, CursorEventContent::Released(_))
693 })
694 }
695
696 pub fn cursor_position_abs(&self) -> Option<PxPosition> {
698 *self.cursor_position_abs
699 }
700
701 pub fn block_cursor(&mut self) {
707 let blocks_non_scroll = self.pointer_changes.iter().any(|change| {
708 !change.is_consumed() && !matches!(change.content, CursorEventContent::Scroll(_))
709 });
710 if blocks_non_scroll {
711 self.cursor_position_abs.take();
712 }
713 self.consume_pointer_changes();
714 }
715
716 pub fn block_all(&mut self) {
718 self.block_cursor();
719 }
720
721 pub fn drag_window(&mut self) {
723 *self.request_window_drag = Some(WindowDragRequest {
724 #[cfg(target_os = "macos")]
725 mouse_press: self.pointer_changes.iter().find_map(|change| {
726 (change.pointer_id == crate::cursor::MOUSE_POINTER_ID
727 && matches!(
728 change.content,
729 CursorEventContent::Pressed(crate::cursor::PressKeyEventType::Left)
730 ))
731 .then_some(change.timestamp)
732 }),
733 });
734 }
735
736 pub fn ime_session(&mut self) -> ImeSession<'_> {
738 ImeSession {
739 request: self.ime_request,
740 }
741 }
742}
743
744pub struct KeyboardInput<'a> {
750 pub computed_data: ComputedData,
752 pub keyboard_events: &'a mut Vec<crate::KeyboardEvent>,
754 pub key_modifiers: winit::keyboard::ModifiersState,
756 pub(crate) ime_request: &'a mut Option<ImeRequest>,
757}
758
759impl KeyboardInput<'_> {
760 pub fn block_keyboard(&mut self) {
762 self.keyboard_events.clear();
763 }
764
765 pub fn ime_session(&mut self) -> ImeSession<'_> {
767 ImeSession {
768 request: self.ime_request,
769 }
770 }
771}
772
773pub struct ImeInput<'a> {
778 pub computed_data: ComputedData,
780 pub ime_events: &'a mut Vec<winit::event::Ime>,
782 pub(crate) ime_request: &'a mut Option<ImeRequest>,
783}
784
785impl ImeInput<'_> {
786 pub fn block_ime(&mut self) {
788 self.ime_events.clear();
789 }
790
791 pub fn ime_session(&mut self) -> ImeSession<'_> {
793 ImeSession {
794 request: self.ime_request,
795 }
796 }
797}
798
799#[derive(Default, Debug)]
803pub(crate) struct WindowRequests {
804 pub cursor_icon: CursorIcon,
808 pub ime_request: Option<ImeRequest>,
813 pub request_window_drag: Option<WindowDragRequest>,
814}
815
816#[derive(Clone, Copy, Debug)]
817pub(crate) struct WindowDragRequest {
818 #[cfg(target_os = "macos")]
819 pub mouse_press: Option<Instant>,
820}
821
822impl WindowRequests {
823 pub(crate) fn settle(&mut self, mut next: Self) {
824 next.request_window_drag = next.request_window_drag.or(self.request_window_drag);
825 if let (Some(previous), Some(request)) = (&self.ime_request, &mut next.ime_request) {
826 request.show_keyboard |=
827 previous.show_keyboard && previous.client_id == request.client_id;
828 if previous.client_id == request.client_id && previous.text_state == request.text_state
829 {
830 request.change_cause = previous.change_cause;
831 }
832 }
833 *self = next;
834 }
835}
836
837pub struct ImeSession<'a> {
839 request: &'a mut Option<ImeRequest>,
840}
841
842impl ImeSession<'_> {
843 pub fn update(&mut self, mut request: ImeRequest) {
845 request.show_keyboard |= self
846 .request
847 .as_ref()
848 .is_some_and(|request| request.show_keyboard);
849 *self.request = Some(request);
850 }
851
852 pub fn show(&mut self, mut request: ImeRequest) {
854 request.show_keyboard = true;
855 self.update(request);
856 }
857
858 pub fn clear(&mut self) {
860 *self.request = None;
861 }
862}
863
864#[derive(Clone, Debug, PartialEq)]
867pub struct ImeRequest {
868 pub size: PxSize,
870 pub local_position: PxPosition,
872 pub text_state: winit::event::ImeTextState,
874 pub options: winit::window::ImeOptions,
876 pub(crate) change_cause: winit::event::ImeChangeCause,
877 pub(crate) show_keyboard: bool,
878 pub(crate) client_id: Option<crate::focus::FocusHandleId>,
879 pub(crate) position: Option<PxPosition>,
880}
881
882impl ImeRequest {
883 pub fn new(size: PxSize) -> Self {
885 Self {
886 size,
887 local_position: PxPosition::ZERO,
888 text_state: winit::event::ImeTextState::default(),
889 options: winit::window::ImeOptions::default(),
890 change_cause: winit::event::ImeChangeCause::Other,
891 show_keyboard: false,
892 client_id: None,
893 position: None,
894 }
895 }
896
897 pub fn with_local_position(mut self, local_position: PxPosition) -> Self {
899 self.local_position = local_position;
900 self
901 }
902
903 pub fn with_text_state(mut self, text_state: winit::event::ImeTextState) -> Self {
905 self.text_state = text_state;
906 self
907 }
908
909 pub fn with_options(mut self, options: winit::window::ImeOptions) -> Self {
911 self.options = options;
912 self
913 }
914}
915
916fn apply_layout_placements(
917 placements: &[(u64, PxPosition)],
918 tree: &ComponentNodeTree,
919 children: &[NodeId],
920 component_node_metadatas: &mut ComponentNodeMetaDatas,
921) {
922 let positions: HashMap<_, _> = placements
923 .iter()
924 .enumerate()
925 .map(|(order, (key, position))| (*key, (*position, order as u64)))
926 .collect();
927 for child_id in children {
928 let placement = tree
929 .get(*child_id)
930 .and_then(|child| positions.get(&child.get().instance_key))
931 .copied();
932 if let Some((position, order)) = placement {
933 place_node(*child_id, position, order, component_node_metadatas);
934 continue;
935 }
936 let metadata = component_node_metadatas.entry_or_default(*child_id);
937 let changed = metadata.rel_position.is_some();
938 metadata.rel_position = None;
939 metadata.placement_order = None;
940 if changed {
941 component_node_metadatas.mark_geometry_dirty(*child_id);
942 }
943 }
944}
945
946#[derive(Clone, Default)]
947pub(super) struct CachedLayoutChildren(Option<Arc<CachedLayoutChildList>>);
948
949struct CachedLayoutChildList {
950 entries: Box<[(u64, ChildMeasure)]>,
951 indices: HashMap<u64, usize>,
952}
953
954impl CachedLayoutChildren {
955 fn new(entries: Vec<(u64, ChildMeasure)>) -> Self {
956 if entries.is_empty() {
957 return Self::default();
958 }
959 let indices = if entries.len() <= 4 {
960 HashMap::default()
961 } else {
962 entries
963 .iter()
964 .enumerate()
965 .map(|(index, &(key, _))| (key, index))
966 .collect()
967 };
968 Self(Some(Arc::new(CachedLayoutChildList {
969 entries: entries.into_boxed_slice(),
970 indices,
971 })))
972 }
973
974 fn entries(&self) -> &[(u64, ChildMeasure)] {
975 self.0.as_deref().map_or(&[], |list| &list.entries)
976 }
977
978 fn index_of(&self, key: u64) -> Option<usize> {
979 let list = self.0.as_ref()?;
980 if list.indices.is_empty() {
981 list.entries.iter().position(|&(entry, _)| entry == key)
982 } else {
983 list.indices.get(&key).copied()
984 }
985 }
986}
987
988fn share_placements(placements: &[(u64, PxPosition)]) -> Option<Arc<[(u64, PxPosition)]>> {
989 (!placements.is_empty()).then(|| Arc::from(placements))
990}
991
992#[derive(Clone)]
993struct MeasuredNodeLayout {
994 size: ComputedData,
995 placements: Vec<(u64, PxPosition)>,
996 base_placements: Option<Arc<[(u64, PxPosition)]>>,
997 measured_children: HashMap<NodeId, crate::layout::ChildMeasure>,
998 intrinsic_dependencies: bool,
999 draw_layout: NodeDrawLayout,
1000}
1001
1002struct MeasureLayoutContext<'a, 'ctx> {
1003 tree: &'a ComponentNodeTree,
1004 children: &'a [NodeId],
1005 layout_ctx: Option<&'a LayoutContext<'ctx>>,
1006}
1007
1008fn measure_base_layout(
1009 policy: &dyn LayoutModifierDyn,
1010 layout_ctx: &MeasureLayoutContext<'_, '_>,
1011 metadatas: &mut ComponentNodeMetaDatas,
1012 constraint: &Constraint,
1013) -> Result<MeasuredNodeLayout, MeasurementError> {
1014 let mut input = LayoutInput::new(
1015 layout_ctx.tree,
1016 ParentConstraint::new(constraint),
1017 layout_ctx.children,
1018 layout_ctx.layout_ctx,
1019 );
1020 let layout_result = {
1021 let mut scope = input.measure_scope(metadatas);
1022 policy.measure_dyn(&mut scope)?
1023 };
1024 Ok(MeasuredNodeLayout {
1025 size: layout_result.size,
1026 base_placements: share_placements(&layout_result.placements),
1027 placements: layout_result.placements,
1028 intrinsic_dependencies: input.has_intrinsic_dependencies(),
1029 measured_children: input.take_measured_children(),
1030 draw_layout: NodeDrawLayout {
1031 layers: None,
1032 base_constraint: *constraint,
1033 base_size: layout_result.size,
1034 },
1035 })
1036}
1037
1038fn measure_with_layout_modifiers(
1039 modifiers: &[Arc<dyn LayoutModifierNode>],
1040 layout_ctx: &MeasureLayoutContext<'_, '_>,
1041 constraint: &Constraint,
1042 base: &mut dyn FnMut(&Constraint) -> Result<MeasuredNodeLayout, MeasurementError>,
1043) -> Result<MeasuredNodeLayout, MeasurementError> {
1044 if modifiers.is_empty() {
1045 return base(constraint);
1046 }
1047
1048 struct ModifierChildRunner<'a, 'b> {
1049 next: &'b mut dyn FnMut(&Constraint) -> Result<MeasuredNodeLayout, MeasurementError>,
1050 last: Option<MeasuredNodeLayout>,
1051 placements: Vec<(u64, PxPosition)>,
1052 position: Option<PxPosition>,
1053 _marker: std::marker::PhantomData<&'a ()>,
1054 }
1055
1056 impl LayoutModifierChild for ModifierChildRunner<'_, '_> {
1057 fn measure(&mut self, constraint: &Constraint) -> Result<ComputedData, MeasurementError> {
1058 let measured = (self.next)(constraint)?;
1059 let size = measured.size;
1060 self.last = Some(measured);
1061 self.placements.clear();
1062 self.position = None;
1063 Ok(size)
1064 }
1065
1066 fn place(&mut self, position: PxPosition) {
1067 self.position = Some(position);
1068 let measured = self
1069 .last
1070 .as_ref()
1071 .expect("layout modifier child must be measured before placement");
1072 for (instance_key, child_position) in &measured.placements {
1073 self.placements
1074 .push((*instance_key, position + *child_position));
1075 }
1076 }
1077 }
1078
1079 let head = &modifiers[0];
1080 let tail = &modifiers[1..];
1081 let mut next = |next_constraint: &Constraint| {
1082 measure_with_layout_modifiers(tail, layout_ctx, next_constraint, base)
1083 };
1084 let mut input = LayoutInput::new(
1085 layout_ctx.tree,
1086 ParentConstraint::new(constraint),
1087 layout_ctx.children,
1088 layout_ctx.layout_ctx,
1089 );
1090 let modifier_input = LayoutModifierInput {
1091 layout_input: &input,
1092 };
1093 let mut child = ModifierChildRunner {
1094 next: &mut next,
1095 last: None,
1096 placements: Vec::new(),
1097 position: None,
1098 _marker: std::marker::PhantomData,
1099 };
1100 let size = head.measure_content(&modifier_input, &mut child)?.size;
1101 if let Some(measured) = child.last.as_ref() {
1102 input.extend_measured_children(measured.measured_children.clone());
1103 }
1104 let mut draw_layout = child
1105 .last
1106 .as_ref()
1107 .map(|measured| measured.draw_layout.clone())
1108 .unwrap_or_default();
1109 let bounds = child
1110 .position
1111 .zip(child.last.as_ref())
1112 .map(|(position, measured)| DrawLayoutBounds {
1113 position,
1114 size: measured.size,
1115 });
1116 let mut layers = draw_layout.layers.as_deref().unwrap_or_default().to_vec();
1117 for layer in &mut layers {
1118 *layer = layer.zip(child.position).map(|(mut layer, position)| {
1119 layer.position = layer.position + position;
1120 layer
1121 });
1122 }
1123 layers.insert(0, bounds);
1124 draw_layout.layers = Some(layers.into());
1125 Ok(MeasuredNodeLayout {
1126 size,
1127 placements: child.placements,
1128 base_placements: child
1129 .last
1130 .as_ref()
1131 .and_then(|measured| measured.base_placements.clone()),
1132 intrinsic_dependencies: input.has_intrinsic_dependencies()
1133 || child
1134 .last
1135 .as_ref()
1136 .is_some_and(|measured| measured.intrinsic_dependencies),
1137 measured_children: input.take_measured_children(),
1138 draw_layout,
1139 })
1140}
1141
1142fn relayout_base_layout(
1143 policy: &dyn LayoutModifierDyn,
1144 modifiers: &[Arc<dyn LayoutModifierNode>],
1145 layout_ctx: &MeasureLayoutContext<'_, '_>,
1146 entry: &LayoutSnapshotEntry,
1147 parent_constraint: &Constraint,
1148 update_placements: bool,
1149) -> Option<MeasuredNodeLayout> {
1150 let _phase = push_phase(RuntimePhase::Place);
1151 let children = layout_ctx.children;
1152 if entry.children.entries().len() != children.len() {
1153 return None;
1154 }
1155
1156 let child_sizes: HashMap<NodeId, ComputedData> = children
1157 .iter()
1158 .copied()
1159 .zip(
1160 entry
1161 .children
1162 .entries()
1163 .iter()
1164 .map(|(_, measure)| measure.size),
1165 )
1166 .collect();
1167 let scope = PlacementScope::new(
1168 layout_ctx.tree,
1169 ParentConstraint::new(&entry.draw_layout.base_constraint),
1170 children,
1171 &child_sizes,
1172 entry.draw_layout.base_size,
1173 );
1174 let placements = if update_placements {
1175 policy
1176 .place_children_dyn(&scope, &PlacementResult::new())?
1177 .into_placements()
1178 } else {
1179 entry
1180 .base_placements
1181 .as_deref()
1182 .unwrap_or_default()
1183 .to_vec()
1184 };
1185 let measured_children = children
1186 .iter()
1187 .copied()
1188 .zip(entry.children.entries().iter().map(|&(_, measure)| measure))
1189 .collect();
1190 let base_layout = MeasuredNodeLayout {
1191 size: entry.draw_layout.base_size,
1192 base_placements: share_placements(&placements),
1193 placements,
1194 measured_children,
1195 intrinsic_dependencies: entry.intrinsic_dependencies,
1196 draw_layout: NodeDrawLayout {
1197 layers: None,
1198 base_constraint: entry.draw_layout.base_constraint,
1199 base_size: entry.draw_layout.base_size,
1200 },
1201 };
1202 let mut base = |constraint: &Constraint| {
1205 if *constraint != entry.draw_layout.base_constraint {
1206 return Err(MeasurementError::MeasureFnFailed(
1207 "cached content constraints changed".into(),
1208 ));
1209 }
1210 Ok(base_layout.clone())
1211 };
1212 let measured =
1213 measure_with_layout_modifiers(modifiers, layout_ctx, parent_constraint, &mut base).ok()?;
1214 (measured.size == entry.layout_result.size).then_some(measured)
1215}
1216
1217fn save_measured_snapshot(
1218 instance_key: u64,
1219 constraint: &Constraint,
1220 layout: &MeasureLayoutContext<'_, '_>,
1221 previous: Option<&LayoutSnapshotEntry>,
1222 measured: MeasuredNodeLayout,
1223) {
1224 let Some(layout_ctx) = layout.layout_ctx else {
1225 return;
1226 };
1227 let consumed_insets = layout_ctx.consumed_insets.get();
1228 let child_measurements = layout.children.iter().map(|id| {
1229 let measurement = measured.measured_children.get(id)?;
1230 measurement
1231 .consistent
1232 .then(|| (layout.tree[*id].get().instance_key, *measurement))
1233 });
1234 let unchanged = previous.is_some_and(|previous| {
1235 previous.constraint_key == *constraint
1236 && previous.consumed_insets == consumed_insets
1237 && previous.layout_result.size == measured.size
1238 && previous.layout_result.placements == measured.placements
1239 && previous.base_placements == measured.base_placements
1240 && previous.intrinsic_dependencies == measured.intrinsic_dependencies
1241 && previous.draw_layout == measured.draw_layout
1242 && child_measurements
1243 .clone()
1244 .eq(previous.children.entries().iter().copied().map(Some))
1245 });
1246 if unchanged {
1247 layout_ctx.acknowledge_deferred_invalidation(instance_key);
1248 } else if let Some(children) = child_measurements.collect::<Option<Vec<_>>>() {
1249 layout_ctx.insert_snapshot(
1250 instance_key,
1251 LayoutSnapshotEntry {
1252 constraint_key: *constraint,
1253 consumed_insets,
1254 children: CachedLayoutChildren::new(children),
1255 layout_result: LayoutResult {
1256 size: measured.size,
1257 placements: measured.placements,
1258 },
1259 base_placements: measured.base_placements,
1260 intrinsic_dependencies: measured.intrinsic_dependencies,
1261 draw_layout: measured.draw_layout,
1262 },
1263 );
1264 layout_ctx.inc_cache_store_count();
1265 } else {
1266 layout_ctx.remove_snapshot(instance_key);
1267 layout_ctx.inc_cache_drop_non_cacheable_count();
1268 }
1269}
1270
1271pub(crate) fn measure_node(
1273 node_id: NodeId,
1274 parent_constraint: &Constraint,
1275 tree: &ComponentNodeTree,
1276 component_node_metadatas: &mut ComponentNodeMetaDatas,
1277 layout_ctx: Option<&LayoutContext<'_>>,
1278) -> Result<ComputedData, MeasurementError> {
1279 let node_data_ref = tree
1280 .get(node_id)
1281 .ok_or(MeasurementError::NodeNotFoundInTree)?;
1282 let node_data = node_data_ref.get();
1283 #[cfg(feature = "profiling")]
1284 let mut profiler_guard = Some(ProfilerScopeGuard::new(
1285 ProfilerPhase::Measure,
1286 Some(node_id),
1287 node_data_ref.parent(),
1288 Some(node_data.fn_name),
1289 ));
1290
1291 #[cfg(feature = "profiling")]
1292 if !layout_ctx.is_some_and(|context| context.intrinsic) {
1293 component_node_metadatas.profiling_dirty.insert(node_id);
1294 }
1295 let children = direct_layout_children(node_id, tree);
1296 let timer = Instant::now();
1297
1298 debug!(
1299 "Measuring node {} with {} children, parent constraint: {:?}",
1300 node_data.fn_name,
1301 children.len(),
1302 parent_constraint
1303 );
1304
1305 let prepare_measurement = || {
1306 let node = push_current_node_with_instance_logic_id(
1307 node_id,
1308 node_data.instance_logic_id,
1309 node_data.fn_name,
1310 );
1311 let instance = push_current_component_instance_key(nearest_replay_boundary_instance_key(
1312 node_id, tree,
1313 ));
1314 let measured = push_measured_node_instance_key(
1315 layout_ctx
1316 .and_then(|context| context.state_reader_instance_key)
1317 .unwrap_or(node_data.instance_key),
1318 );
1319 let phase = push_phase(RuntimePhase::Measure);
1320 (
1321 (phase, measured, instance, node),
1322 node_data.modifier.layout_modifiers(),
1323 )
1324 };
1325 let mut measurement = None;
1326 let layout_node = &node_data.layout_node;
1327 let snapshot = layout_ctx.and_then(|context| context.snapshot(node_data.instance_key));
1328 if let Some(layout_ctx) = layout_ctx {
1329 layout_ctx.inc_measure_node_calls();
1330 if let Some(entry) = snapshot.as_deref() {
1331 let path = layout_ctx.dirty_paths.and_then(|paths| paths.get(&node_id));
1332 let deferred = layout_ctx.deferred_invalidation(node_data.instance_key);
1333 let same_constraint = entry.constraint_key == *parent_constraint;
1334 let node_self_measure_dirty = entry.consumed_insets != layout_ctx.consumed_insets.get()
1335 || path.is_some_and(|path| path.measure)
1336 || deferred.as_ref().is_some_and(|pending| pending.measure);
1337 let node_self_placement_dirty = path.is_some_and(|path| path.placement)
1338 || deferred.as_ref().is_some_and(|pending| pending.placement);
1339 let node_effective_dirty = path.is_some()
1340 || deferred
1341 .as_ref()
1342 .is_some_and(|pending| !pending.children.is_empty());
1343 let cached_children = entry.children.entries();
1344 let can_try_reuse = !node_self_measure_dirty
1345 && (!node_effective_dirty || !entry.intrinsic_dependencies)
1346 && cached_children.len() == children.len();
1347 if can_try_reuse {
1348 if same_constraint
1349 && !node_self_placement_dirty
1350 && !node_effective_dirty
1351 && component_node_metadatas
1352 .get(&node_id)
1353 .is_some_and(|metadata| {
1354 metadata.computed_data == Some(entry.layout_result.size)
1355 })
1356 {
1357 component_node_metadatas
1358 .entry_or_default(node_id)
1359 .layout_cache_hit = true;
1360 layout_ctx.inc_cache_hit_direct();
1361 return Ok(entry.layout_result.size);
1362 }
1363 let dirty_children = path
1364 .map(|path| path.children.as_slice())
1365 .into_iter()
1366 .flatten()
1367 .filter_map(|&id| {
1368 layout_ctx.inc_dirty_child_checked();
1369 let index = entry.children.index_of(tree[id].get().instance_key)?;
1370 Some((index, id))
1371 })
1372 .chain(
1373 deferred
1374 .iter()
1375 .flat_map(|pending| pending.children.iter())
1376 .filter_map(|key| {
1377 let index = entry.children.index_of(*key)?;
1378 let &id = children.get(index)?;
1379 if tree[id].get().instance_key != *key
1380 || layout_ctx
1381 .dirty_paths
1382 .is_some_and(|paths| paths.contains_key(&id))
1383 {
1384 return None;
1385 }
1386 layout_ctx.inc_dirty_child_checked();
1387 Some((index, id))
1388 }),
1389 );
1390
1391 let mut child_size_changed = false;
1392 for (index, child_id) in dirty_children {
1393 let (_, previous) = cached_children[index];
1394 let size = layout_ctx.with_consumed_insets(previous.consumed_insets, || {
1395 measure_node(
1396 child_id,
1397 &previous.constraint,
1398 tree,
1399 component_node_metadatas,
1400 Some(layout_ctx),
1401 )
1402 })?;
1403 if size != previous.size {
1404 child_size_changed = true;
1405 break;
1406 }
1407 }
1408 if child_size_changed {
1409 layout_ctx.inc_cache_miss_child_size();
1410 } else {
1411 if same_constraint
1412 && !node_self_placement_dirty
1413 && component_node_metadatas
1414 .get(&node_id)
1415 .is_some_and(|metadata| {
1416 metadata.computed_data == Some(entry.layout_result.size)
1417 })
1418 {
1419 component_node_metadatas
1420 .entry_or_default(node_id)
1421 .layout_cache_hit = true;
1422 layout_ctx.acknowledge_deferred_invalidation(node_data.instance_key);
1423 layout_ctx.inc_cache_hit_boundary();
1424 return Ok(entry.layout_result.size);
1425 }
1426 let cached_result = &entry.layout_result;
1427 let needs_relayout = node_self_placement_dirty || !same_constraint;
1428 let relayout = if needs_relayout {
1429 let (_, layout_modifiers) =
1430 measurement.get_or_insert_with(&prepare_measurement);
1431 crate::runtime::clear_phase_state_reads(
1432 node_data.instance_key,
1433 crate::runtime::ReadPhase::Place,
1434 );
1435 relayout_base_layout(
1436 layout_node.as_ref(),
1437 layout_modifiers,
1438 &MeasureLayoutContext {
1439 tree,
1440 children: &children,
1441 layout_ctx: Some(layout_ctx),
1442 },
1443 entry,
1444 parent_constraint,
1445 node_self_placement_dirty,
1446 )
1447 } else {
1448 None
1449 };
1450 if needs_relayout && relayout.is_none() {
1451 if node_self_placement_dirty {
1452 layout_ctx.inc_cache_miss_dirty_self();
1453 }
1454 } else {
1455 let (placements, draw_layout, base_placements) = relayout
1456 .map(|measured| {
1457 (
1458 measured.placements,
1459 measured.draw_layout,
1460 measured.base_placements,
1461 )
1462 })
1463 .unwrap_or_else(|| {
1464 (
1465 cached_result.placements.clone(),
1466 entry.draw_layout.clone(),
1467 entry.base_placements.clone(),
1468 )
1469 });
1470 apply_layout_placements(
1471 &placements,
1472 tree,
1473 &children,
1474 component_node_metadatas,
1475 );
1476 if component_node_metadatas
1477 .get(&node_id)
1478 .is_some_and(|metadata| metadata.draw_layout != draw_layout)
1479 {
1480 component_node_metadatas.mark_paint_dirty(node_id);
1481 }
1482 if let Some(metadata) = component_node_metadatas.get_mut(&node_id) {
1483 metadata.computed_data = Some(cached_result.size);
1484 metadata.paint_dirty |= metadata.draw_layout != draw_layout;
1485 metadata.draw_layout = draw_layout.clone();
1486 metadata.layout_cache_hit = true;
1487 }
1488 if needs_relayout
1489 && (!same_constraint
1490 || placements != cached_result.placements
1491 || draw_layout != entry.draw_layout
1492 || base_placements != entry.base_placements)
1493 {
1494 layout_ctx.insert_snapshot(
1495 node_data.instance_key,
1496 LayoutSnapshotEntry {
1497 constraint_key: *parent_constraint,
1498 consumed_insets: layout_ctx.consumed_insets.get(),
1499 children: entry.children.clone(),
1500 layout_result: LayoutResult {
1501 size: cached_result.size,
1502 placements,
1503 },
1504 base_placements,
1505 intrinsic_dependencies: entry.intrinsic_dependencies,
1506 draw_layout,
1507 },
1508 );
1509 layout_ctx.inc_cache_store_count();
1510 }
1511 layout_ctx.acknowledge_deferred_invalidation(node_data.instance_key);
1512 layout_ctx.inc_cache_hit_boundary();
1513 return Ok(cached_result.size);
1514 }
1515 }
1516 }
1517 if !same_constraint {
1518 layout_ctx.inc_cache_miss_constraint();
1519 } else if node_self_measure_dirty || node_self_placement_dirty {
1520 layout_ctx.inc_cache_miss_dirty_self();
1521 } else if node_effective_dirty {
1522 layout_ctx.inc_cache_miss_child_size();
1523 } else {
1524 layout_ctx.inc_cache_miss_no_entry();
1525 }
1526 } else {
1527 layout_ctx.inc_cache_miss_no_entry();
1528 }
1529 }
1530
1531 let (_, layout_modifiers) = measurement.get_or_insert_with(prepare_measurement);
1532 if !layout_ctx.is_some_and(|context| context.intrinsic) {
1533 crate::runtime::clear_phase_state_reads(
1534 node_data.instance_key,
1535 crate::runtime::ReadPhase::Measure,
1536 );
1537 crate::runtime::clear_phase_state_reads(
1538 node_data.instance_key,
1539 crate::runtime::ReadPhase::Place,
1540 );
1541 }
1542 let previous_size = reset_frame_metadata(node_id, component_node_metadatas);
1543 let measure_layout_ctx = MeasureLayoutContext {
1544 tree,
1545 children: &children,
1546 layout_ctx,
1547 };
1548 let measured = measure_with_layout_modifiers(
1549 layout_modifiers,
1550 &measure_layout_ctx,
1551 parent_constraint,
1552 &mut |constraint| {
1553 measure_base_layout(
1554 layout_node.as_ref(),
1555 &measure_layout_ctx,
1556 component_node_metadatas,
1557 constraint,
1558 )
1559 },
1560 )
1561 .inspect_err(|_| component_node_metadatas.mark_geometry_dirty(node_id))?;
1562 let size = measured.size;
1563 apply_layout_placements(
1564 &measured.placements,
1565 tree,
1566 &children,
1567 component_node_metadatas,
1568 );
1569
1570 if previous_size != Some(size) {
1571 component_node_metadatas.mark_geometry_dirty(node_id);
1572 }
1573 let metadata = component_node_metadatas.entry_or_default(node_id);
1574 metadata.computed_data = Some(size);
1575 metadata.draw_layout = measured.draw_layout.clone();
1576
1577 #[cfg(feature = "profiling")]
1578 if let Some(guard) = &mut profiler_guard {
1579 guard.set_computed_size(size.width.0, size.height.0);
1580 }
1581
1582 save_measured_snapshot(
1583 node_data.instance_key,
1584 parent_constraint,
1585 &measure_layout_ctx,
1586 snapshot.as_deref(),
1587 measured,
1588 );
1589
1590 debug!(
1591 "Measured node {} in {:?} with size {:?}",
1592 node_data.fn_name,
1593 timer.elapsed(),
1594 size
1595 );
1596
1597 #[cfg(feature = "profiling")]
1598 if let Some(guard) = &mut profiler_guard {
1599 guard.set_computed_size(size.width.0, size.height.0);
1600 }
1601
1602 Ok(size)
1603}
1604
1605pub(crate) fn place_node(
1607 node: indextree::NodeId,
1608 rel_position: PxPosition,
1609 placement_order: u64,
1610 component_node_metadatas: &mut ComponentNodeMetaDatas,
1611) {
1612 let metadata = component_node_metadatas.entry_or_default(node);
1613 let changed = metadata.rel_position != Some(rel_position);
1614 let order_changed = metadata.placement_order != Some(placement_order);
1615 metadata.rel_position = Some(rel_position);
1616 metadata.placement_order = Some(placement_order);
1617 if order_changed {
1618 component_node_metadatas.placement_order_dirty.insert(node);
1619 component_node_metadatas.mark_geometry_dirty(node);
1620 }
1621 if changed {
1622 component_node_metadatas.mark_geometry_dirty(node);
1623 }
1624}
1625
1626#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1629pub struct ComputedData {
1630 pub width: Px,
1632 pub height: Px,
1634}
1635
1636impl Add for ComputedData {
1637 type Output = Self;
1638 fn add(self, rhs: Self) -> Self::Output {
1639 Self {
1640 width: self.width + rhs.width,
1641 height: self.height + rhs.height,
1642 }
1643 }
1644}
1645
1646impl AddAssign for ComputedData {
1647 fn add_assign(&mut self, rhs: Self) {
1648 *self = *self + rhs;
1649 }
1650}
1651
1652impl ComputedData {
1653 pub const ZERO: Self = Self {
1655 width: Px(0),
1656 height: Px(0),
1657 };
1658
1659 pub fn min_from_constraint(constraint: &Constraint) -> Self {
1661 let width = constraint.width.min;
1662 let height = constraint.height.min;
1663 Self { width, height }
1664 }
1665
1666 pub fn min(self, rhs: Self) -> Self {
1668 Self {
1669 width: self.width.min(rhs.width),
1670 height: self.height.min(rhs.height),
1671 }
1672 }
1673
1674 pub fn max(self, rhs: Self) -> Self {
1676 Self {
1677 width: self.width.max(rhs.width),
1678 height: self.height.max(rhs.height),
1679 }
1680 }
1681}