1mod bottom_up;
2mod coordinator_chain;
3pub mod core;
5pub(crate) mod flex_box;
6mod frame_layout_arena;
7pub(crate) mod grid;
8mod live_layout_node;
9mod measure_telemetry;
10mod measured_spare;
11mod placed_root_measurements;
12pub mod policies;
14mod reveal;
15mod semantics_details;
16mod semantics_labels;
17mod semantics_tree;
18mod semantics_update;
19
20use std::{
21 cell::{Cell, RefCell},
22 fmt,
23 mem::size_of,
24 rc::Rc,
25};
26
27use cranpose_core::{
28 Applier, ApplierHost, ConcreteApplierHost, MemoryApplier, Node, NodeError, NodeId, PackedU64,
29 RuntimeHandle,
30};
31use cranpose_foundation::{
32 InvalidationKind, ModifierNodeContext, SemanticsConfiguration, SemanticsWidgetRole,
33};
34use cranpose_ui_graphics::{ProjectiveTransform, layer_transform::layer_transform_to_window};
35use cranpose_ui_layout::{AlignmentLines, Constraints, MeasurePolicy, PlaceTarget, Placement};
36pub(crate) use frame_layout_arena::FrameLayoutArena;
37use frame_layout_arena::VecPools;
38use live_layout_node::{LiveLayoutNode, read_live_layout_node};
39use measured_spare::MeasuredSpare;
40use placed_root_measurements::PlacedRootMeasurements;
41pub use semantics_tree::{
42 SemanticsAction, SemanticsCallback, SemanticsNode, SemanticsPlacement, SemanticsRole,
43 SemanticsText, SemanticsTree,
44};
45use semantics_tree::{modal_takes_space, top_modal_path};
46use web_time::Instant;
47
48#[cfg(test)]
49use self::core::{HorizontalAlignment, VerticalAlignment};
50use self::{
51 coordinator_chain::{CoordinatorChain, CoordinatorFrame},
52 core::{Measurable, Placeable},
53 measure_telemetry::{
54 LayoutStages, layout_measure_telemetry_threshold_ms, log_layout_measure_telemetry,
55 log_node_measure_telemetry,
56 },
57 semantics_update::semantics_placement,
58};
59pub use self::{
60 reveal::can_skip_scroll_reveal_from_applier,
61 semantics_details::SemanticsDetails,
62 semantics_update::{build_semantics_tree_from_applier, update_semantics_tree_from_applier},
63};
64use crate::{
65 modifier::{
66 DimensionConstraint, EdgeInsets, Modifier, ModifierNodeSlices,
67 ModifierNodeSlicesDebugStats, Point, Rect as GeometryRect, ResolvedModifiers, Size,
68 },
69 render_state::AppContext,
70 subcompose_layout::{
71 MeasureCallbacks, MeasuredChildren, SubcomposeLayoutNode, SubcomposeLayoutNodeHandle,
72 },
73 widgets::nodes::{IntrinsicKind, LayoutNode, LayoutParts, LayoutState},
74};
75
76#[derive(Default)]
77pub(crate) struct LayoutNodeContext {
78 invalidations: Vec<InvalidationKind>,
79 update_requested: bool,
80 density: f32,
81}
82
83impl LayoutNodeContext {
84 pub(crate) fn new(density: f32) -> Self {
85 Self {
86 density,
87 ..Self::default()
88 }
89 }
90
91 pub(crate) fn take_invalidations(&mut self) -> Vec<InvalidationKind> {
92 std::mem::take(&mut self.invalidations)
93 }
94}
95
96impl ModifierNodeContext for LayoutNodeContext {
97 fn invalidate(&mut self, kind: InvalidationKind) {
98 if !self.invalidations.contains(&kind) {
99 self.invalidations.push(kind);
100 }
101 }
102
103 fn request_update(&mut self) {
104 self.update_requested = true;
105 }
106
107 fn density(&self) -> f32 {
108 self.density
109 }
110}
111
112#[doc(hidden)]
113pub fn invalidate_all_layout_caches() {
114 crate::render_state::invalidate_layout_cache_epoch();
115}
116
117pub(crate) struct LayoutHost {
120 host: Rc<ConcreteApplierHost<MemoryApplier>>,
121}
122
123impl Default for LayoutHost {
124 fn default() -> Self {
125 Self {
126 host: Rc::new(ConcreteApplierHost::new(MemoryApplier::new())),
127 }
128 }
129}
130
131struct ApplierSlotGuard<'a> {
134 target: &'a mut MemoryApplier,
135 lent: LayoutHost,
136 context: &'a AppContext,
137}
138
139impl<'a> ApplierSlotGuard<'a> {
140 fn new(target: &'a mut MemoryApplier, context: &'a AppContext) -> Self {
141 let lent = context.take_layout_host();
142 std::mem::swap(target, &mut *lent.host.borrow_typed());
143 Self {
144 target,
145 lent,
146 context,
147 }
148 }
149
150 fn host(&self) -> &Rc<ConcreteApplierHost<MemoryApplier>> {
151 &self.lent.host
152 }
153}
154
155impl Drop for ApplierSlotGuard<'_> {
156 fn drop(&mut self) {
157 let host = &self.lent.host;
158 std::mem::swap(self.target, &mut *host.borrow_typed());
159 if Rc::strong_count(host) == 1 {
161 self.context.replace_layout_host(LayoutHost {
162 host: Rc::clone(host),
163 });
164 }
165 }
166}
167
168#[derive(Clone, Copy, PartialEq)]
169struct ModifierChainInputs {
170 density: crate::density::Density,
171 window_root: bool,
172 offset: Point,
173 uses_chain: bool,
174}
175
176struct ModifierChainMeasurement {
177 size: Size,
178 alignment_lines: AlignmentLines,
179 content_offset: Point,
180 offset: Point,
181 window_root: bool,
182 hold: Option<cranpose_ui_layout::ConstraintsHold>,
184 ignores_child_sizes: bool,
187}
188
189#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
192pub struct LayoutAllocationDebugStats {
193 pub layout_box_count: usize,
195 pub layout_box_child_count: usize,
197 pub layout_box_child_capacity: usize,
199 pub layout_box_heap_bytes: usize,
201 pub modifier_slice_count: usize,
203 pub modifier_slice_heap_bytes: usize,
205 pub modifier_draw_command_count: usize,
207 pub modifier_draw_command_capacity: usize,
209 pub modifier_pointer_input_count: usize,
211 pub modifier_pointer_input_capacity: usize,
213 pub modifier_text_content_count: usize,
215 pub modifier_text_style_count: usize,
217 pub modifier_text_layout_options_count: usize,
219 pub modifier_prepared_text_layout_count: usize,
221 pub modifier_graphics_layer_count: usize,
223 pub modifier_graphics_layer_resolver_count: usize,
225 pub semantics_node_count: usize,
227 pub semantics_action_count: usize,
229 pub semantics_action_capacity: usize,
231 pub semantics_child_count: usize,
233 pub semantics_child_capacity: usize,
235 pub semantics_description_count: usize,
237 pub semantics_description_bytes: usize,
239 pub semantics_heap_bytes: usize,
241}
242
243impl LayoutAllocationDebugStats {
244 fn add_modifier_slice(&mut self, stats: ModifierNodeSlicesDebugStats) {
245 self.modifier_slice_count += 1;
246 self.modifier_slice_heap_bytes += stats.heap_bytes;
247 self.modifier_draw_command_count += stats.draw_command_count;
248 self.modifier_draw_command_capacity += stats.draw_command_capacity;
249 self.modifier_pointer_input_count += stats.pointer_input_count;
250 self.modifier_pointer_input_capacity += stats.pointer_input_capacity;
251 self.modifier_text_content_count += usize::from(stats.has_text_content);
252 self.modifier_text_style_count += usize::from(stats.has_text_style);
253 self.modifier_text_layout_options_count += usize::from(stats.has_text_layout_options);
254 self.modifier_prepared_text_layout_count += usize::from(stats.has_prepared_text_layout);
255 self.modifier_graphics_layer_count += usize::from(stats.has_graphics_layer);
256 self.modifier_graphics_layer_resolver_count +=
257 usize::from(stats.has_graphics_layer_resolver);
258 }
259}
260
261#[derive(Debug, Clone)]
263pub struct LayoutTree {
264 root: LayoutBox,
265}
266
267impl LayoutTree {
268 pub fn new(root: LayoutBox) -> Self {
270 Self { root }
271 }
272
273 pub fn root(&self) -> &LayoutBox {
275 &self.root
276 }
277
278 pub fn root_mut(&mut self) -> &mut LayoutBox {
280 &mut self.root
281 }
282
283 pub fn into_root(self) -> LayoutBox {
285 self.root
286 }
287
288 pub fn debug_allocation_stats(&self) -> LayoutAllocationDebugStats {
290 let mut stats = LayoutAllocationDebugStats::default();
291 record_layout_box_allocation_stats(&self.root, &mut stats);
292 stats
293 }
294}
295
296#[derive(Debug, Clone)]
298pub struct LayoutBox {
299 pub node_id: NodeId,
301 pub node_generation: u32,
303 pub rect: GeometryRect,
306 pub content_offset: Point,
308 pub node_data: LayoutNodeData,
310 pub children: Vec<Self>,
312}
313
314impl LayoutBox {
315 pub fn new(
317 node_id: NodeId,
318 rect: GeometryRect,
319 content_offset: Point,
320 node_data: LayoutNodeData,
321 children: Vec<Self>,
322 ) -> Self {
323 Self {
324 node_id,
325 node_generation: 0,
326 rect,
327 content_offset,
328 node_data,
329 children,
330 }
331 }
332}
333
334#[derive(Debug, Clone)]
336pub struct LayoutNodeData {
337 #[cfg(feature = "inspection")]
339 pub source_trace: Rc<[cranpose_core::source_trace::SourceLocation]>,
340 pub modifier: Modifier,
342 pub resolved_modifiers: ResolvedModifiers,
344 pub modifier_slices: Rc<ModifierNodeSlices>,
347 pub semantics: Option<Rc<SemanticsConfiguration>>,
349 pub kind: LayoutNodeKind,
351}
352
353impl LayoutNodeData {
354 pub fn new(
356 modifier: Modifier,
357 resolved_modifiers: ResolvedModifiers,
358 modifier_slices: Rc<ModifierNodeSlices>,
359 semantics: Option<Rc<SemanticsConfiguration>>,
360 kind: LayoutNodeKind,
361 ) -> Self {
362 Self {
363 #[cfg(feature = "inspection")]
364 source_trace: Rc::default(),
365 modifier,
366 resolved_modifiers,
367 modifier_slices,
368 semantics,
369 kind,
370 }
371 }
372
373 pub fn semantics(&self) -> Option<&SemanticsConfiguration> {
376 self.semantics.as_deref()
377 }
378
379 pub fn resolved_modifiers(&self) -> ResolvedModifiers {
381 self.resolved_modifiers
382 }
383
384 pub fn modifier_slices(&self) -> &ModifierNodeSlices {
387 &self.modifier_slices
388 }
389}
390
391#[derive(Clone)]
398pub enum LayoutNodeKind {
399 Layout,
401 Subcompose,
403 Spacer,
405 Button {
407 on_click: Rc<RefCell<dyn FnMut()>>,
409 },
410 Unknown,
412}
413
414impl fmt::Debug for LayoutNodeKind {
415 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416 match self {
417 Self::Layout => f.write_str("Layout"),
418 Self::Subcompose => f.write_str("Subcompose"),
419 Self::Spacer => f.write_str("Spacer"),
420 Self::Button { .. } => f.write_str("Button"),
421 Self::Unknown => f.write_str("Unknown"),
422 }
423 }
424}
425
426pub trait LayoutEngine {
428 fn compute_layout(&mut self, root: NodeId, max_size: Size) -> Result<LayoutTree, NodeError>;
430}
431
432impl LayoutEngine for MemoryApplier {
433 fn compute_layout(&mut self, root: NodeId, max_size: Size) -> Result<LayoutTree, NodeError> {
434 let measurements = measure_layout(self, root, max_size)?;
435 measurements
436 .into_layout_tree()
437 .ok_or(NodeError::MissingContext {
438 id: root,
439 reason: "layout tree was not requested",
440 })
441 }
442}
443
444#[derive(Debug, Clone)]
446pub struct LayoutMeasurements {
447 root: Rc<MeasuredNode>,
448 semantics: Option<Box<SemanticsTree>>,
451 layout_tree: Option<Box<LayoutTree>>,
452}
453
454impl LayoutMeasurements {
455 fn new(
456 root: Rc<MeasuredNode>,
457 semantics: Option<SemanticsTree>,
458 layout_tree: Option<LayoutTree>,
459 ) -> Self {
460 Self {
461 root,
462 semantics: semantics.map(Box::new),
463 layout_tree: layout_tree.map(Box::new),
464 }
465 }
466
467 pub fn root_size(&self) -> Size {
469 self.root.size
470 }
471
472 pub fn semantics_tree(&self) -> Option<&SemanticsTree> {
474 self.semantics.as_deref()
475 }
476
477 pub fn debug_allocation_stats(&self) -> LayoutAllocationDebugStats {
479 let mut stats = self
480 .layout_tree
481 .as_deref()
482 .map(LayoutTree::debug_allocation_stats)
483 .unwrap_or_default();
484 if let Some(semantics) = &self.semantics {
485 record_semantics_allocation_stats(semantics.root(), &mut stats);
486 }
487 stats
488 }
489
490 pub fn into_layout_tree(self) -> Option<LayoutTree> {
492 self.layout_tree.map(|tree| *tree)
493 }
494
495 pub fn layout_tree(&self) -> Option<LayoutTree> {
497 self.layout_tree.as_deref().cloned()
498 }
499}
500
501pub fn build_semantics_tree_from_layout_tree(layout_tree: &LayoutTree) -> SemanticsTree {
506 SemanticsTree::new(build_semantics_node_from_layout_box(
507 layout_tree.root(),
508 Point::default(),
509 ))
510}
511
512pub fn build_layout_tree_from_applier(
518 applier: &mut MemoryApplier,
519 root: NodeId,
520) -> Result<Option<LayoutTree>, NodeError> {
521 let origin = layout_tree_origin(read_layout_node(applier, root, |state, _| state)?);
522 let mut child_stack = Vec::new();
523 place_layout_box(
524 applier,
525 root,
526 origin,
527 ProjectiveTransform::identity(),
528 &mut child_stack,
529 )
530 .map(|root| root.map(LayoutTree::new))
531}
532
533pub fn has_placed_content(applier: &mut MemoryApplier, root: NodeId) -> Result<bool, NodeError> {
537 walk_placed_boxes(applier, root, |_| std::ops::ControlFlow::Break(()))
538}
539
540pub fn placed_content_extent(
545 applier: &mut MemoryApplier,
546 root: NodeId,
547) -> Result<Option<Size>, NodeError> {
548 let mut extent: Option<Size> = None;
549 walk_placed_boxes(applier, root, |rect| {
550 let (right, bottom) = (rect.x + rect.width, rect.y + rect.height);
551 extent = Some(extent.map_or_else(
552 || Size::new(right, bottom),
553 |extent| Size::new(extent.width.max(right), extent.height.max(bottom)),
554 ));
555 std::ops::ControlFlow::Continue(())
556 })?;
557 Ok(extent)
558}
559
560fn walk_placed_boxes(
565 applier: &mut MemoryApplier,
566 root: NodeId,
567 mut visit: impl FnMut(GeometryRect) -> std::ops::ControlFlow<()>,
568) -> Result<bool, NodeError> {
569 let mut pending: Vec<(NodeId, Point)> = Vec::new();
570 let placed = read_layout_node(applier, root, |state, children| {
571 if state.is_placed() {
572 pending.extend(
573 children
574 .iter()
575 .map(|&child| (child, state.content_offset())),
576 );
577 }
578 })?;
579 if placed.is_none() {
580 return Ok(false);
581 }
582 while let Some((node_id, origin)) = pending.pop() {
583 if crate::modifier::is_window_root(applier, node_id) {
584 continue;
585 }
586 let rect = read_layout_node(applier, node_id, |state, children| {
587 if !state.is_placed() {
588 return None;
589 }
590 let (rect, content) = semantics_placement(&state, Some(origin));
591 pending.extend(children.iter().map(|&child| (child, content)));
592 Some(rect)
593 })?
594 .flatten();
595 if let Some(rect) = rect
596 && rect.width > 0.0
597 && rect.height > 0.0
598 && visit(rect).is_break()
599 {
600 return Ok(true);
601 }
602 }
603 Ok(false)
604}
605
606fn layout_tree_origin(root: Option<LayoutState>) -> Point {
607 let Some(state) = root else {
608 return Point::default();
609 };
610 let position = state.position();
611 Point {
612 x: -position.x,
613 y: -position.y,
614 }
615}
616
617fn finish_placement(applier: &mut MemoryApplier, root: NodeId, context: &AppContext) {
620 if applier
621 .with_node::<LayoutNode, _>(root, |node| {
622 node.set_position(Point::default(), None, context);
623 })
624 .is_err()
625 {
626 let _ = applier.with_node::<SubcomposeLayoutNode, _>(root, |node| {
627 node.set_position(Point::default(), None, context);
628 });
629 }
630 if let Some(pass) = context.placement_pass().with_unplaced_nodes() {
631 record_unplaced_parents(applier, root, pass, context);
632 }
633}
634
635#[inline(never)]
639fn record_unplaced_parents(
640 applier: &mut MemoryApplier,
641 root: NodeId,
642 pass: u64,
643 context: &AppContext,
644) {
645 let mut parents = vec![root];
646 let mut children = Vec::new();
647 while let Some(parent) = parents.pop() {
648 children.clear();
649 if !matches!(
650 read_layout_node(applier, parent, |_, ids| children.extend_from_slice(ids)),
651 Ok(Some(()))
652 ) {
653 continue;
654 }
655 for &child in &children {
656 match read_layout_node(applier, child, |state, _| state.unplaced_in(pass)) {
657 Ok(Some(true)) => context.record_geometry_scene_node(parent),
658 Ok(Some(false)) => parents.push(child),
659 Ok(None) | Err(_) => {}
660 }
661 }
662 }
663}
664
665fn read_layout_node<R>(
666 applier: &mut MemoryApplier,
667 node_id: NodeId,
668 mut read: impl FnMut(LayoutState, &[NodeId]) -> R,
669) -> Result<Option<R>, NodeError> {
670 read_live_layout_node(applier, node_id, |node| {
671 node.with_children(|children| read(node.state(), children))
672 })
673}
674
675fn snapshot_node_data(
676 applier: &mut MemoryApplier,
677 node_id: NodeId,
678 top_left: Point,
679 size: Size,
680 parent_transform: ProjectiveTransform,
681) -> Result<(LayoutNodeData, ProjectiveTransform), NodeError> {
682 let info = runtime_metadata_for(applier, node_id)?;
683 let kind = layout_kind_from_metadata(node_id, &info);
684 let RuntimeNodeMetadata {
685 modifier,
686 resolved_modifiers,
687 modifier_slices,
688 semantics,
689 ..
690 } = info;
691
692 let window_transform = modifier_slices
693 .graphics_layer()
694 .map_or(parent_transform, |layer| {
695 layer_transform_to_window(
696 parent_transform,
697 top_left,
698 modifier_slices.layer_bounds(size),
699 &layer,
700 )
701 });
702 modifier_slices.publish_window_geometry(top_left, window_transform, size);
703
704 let data = LayoutNodeData {
705 #[cfg(feature = "inspection")]
706 source_trace: applier
707 .with_node::<LayoutNode, _>(node_id, |node| Rc::clone(&node.source_trace))
708 .unwrap_or_default(),
709 modifier,
710 resolved_modifiers,
711 modifier_slices,
712 semantics,
713 kind,
714 };
715 Ok((data, window_transform))
716}
717
718fn place_layout_box(
723 applier: &mut MemoryApplier,
724 node_id: NodeId,
725 parent_content_origin: Point,
726 parent_transform: ProjectiveTransform,
727 child_stack: &mut Vec<NodeId>,
728) -> Result<Option<LayoutBox>, NodeError> {
729 let first_child = child_stack.len();
730 let Some(state) = read_layout_node(applier, node_id, |state, children| {
731 if state.is_placed() {
732 child_stack.extend_from_slice(children);
733 }
734 state
735 })?
736 else {
737 return Ok(None);
738 };
739 if !state.is_placed() {
740 return Ok(None);
741 }
742
743 let top_left = Point {
744 x: parent_content_origin.x + state.position().x,
745 y: parent_content_origin.y + state.position().y,
746 };
747 let rect = GeometryRect {
748 x: top_left.x,
749 y: top_left.y,
750 width: state.size().width,
751 height: state.size().height,
752 };
753 let (data, window_transform) =
754 snapshot_node_data(applier, node_id, top_left, state.size(), parent_transform)?;
755 let child_origin = Point {
756 x: top_left.x + state.content_offset().x,
757 y: top_left.y + state.content_offset().y,
758 };
759 let end = child_stack.len();
760 let mut children = Vec::with_capacity(end - first_child);
761 for index in first_child..end {
762 let child_id = child_stack[index];
763 if crate::modifier::is_window_root(applier, child_id) {
764 continue;
765 }
766 if let Some(child) = place_layout_box(
767 applier,
768 child_id,
769 child_origin,
770 window_transform,
771 child_stack,
772 )? {
773 children.push(child);
774 }
775 }
776 child_stack.truncate(first_child);
777
778 Ok(Some(LayoutBox {
779 node_generation: applier.node_generation(node_id),
780 ..LayoutBox::new(node_id, rect, state.content_offset(), data, children)
781 }))
782}
783
784pub fn top_modal_from_applier(
789 applier: &mut MemoryApplier,
790 root: NodeId,
791) -> Result<Option<NodeId>, NodeError> {
792 enum Step {
797 Enter { node: NodeId, child: bool },
798 Modal(NodeId),
799 }
800
801 fn push_placed(
802 steps: &mut Vec<Step>,
803 node: NodeId,
804 reach: cranpose_foundation::SemanticsReach,
805 size: Size,
806 children: impl IntoIterator<Item = NodeId>,
807 ) {
808 if reach.hidden {
809 return;
810 }
811 if reach.is_modal && modal_takes_space(size) {
812 steps.push(Step::Modal(node));
813 }
814 steps.extend(
815 children
816 .into_iter()
817 .map(|node| Step::Enter { node, child: true }),
818 );
819 }
820
821 let mut steps = vec![Step::Enter {
822 node: root,
823 child: false,
824 }];
825 while let Some(step) = steps.pop() {
826 let (node_id, child) = match step {
827 Step::Modal(node) => return Ok(Some(node)),
828 Step::Enter { node, child } => (node, child),
829 };
830 let node = match applier.get_mut(node_id) {
831 Ok(node) => node.as_any_mut(),
832 Err(NodeError::Missing { .. }) => continue,
833 Err(error) => return Err(error),
834 };
835 if let Some(layout) = node.downcast_mut::<LayoutNode>() {
836 let state = layout.layout_state();
837 if state.is_placed() && !(child && layout.is_window_root()) {
838 let children = layout.children.iter().copied();
839 push_placed(
840 &mut steps,
841 node_id,
842 layout.semantics_reach(),
843 state.size(),
844 children,
845 );
846 }
847 } else if let Some(subcompose) = node.downcast_mut::<SubcomposeLayoutNode>() {
848 let state = subcompose.layout_state();
849 if state.is_placed() {
850 let reach = subcompose.semantics_reach();
851 subcompose.with_active_children(|children| {
852 push_placed(
853 &mut steps,
854 node_id,
855 reach,
856 state.size(),
857 children.iter().copied(),
858 );
859 });
860 }
861 }
862 }
863 Ok(None)
864}
865
866#[derive(Clone, Copy, Debug, PartialEq, Eq)]
868pub struct MeasureLayoutOptions {
869 pub collect_semantics: bool,
871 pub build_layout_tree: bool,
873}
874
875impl Default for MeasureLayoutOptions {
876 fn default() -> Self {
877 Self {
878 collect_semantics: true,
879 build_layout_tree: true,
880 }
881 }
882}
883
884pub fn tree_needs_layout(applier: &mut dyn Applier, root: NodeId) -> Result<bool, NodeError> {
892 Ok(applier.get_mut(root)?.layout_dirty())
893}
894
895pub fn tree_needs_semantics(applier: &mut dyn Applier, root: NodeId) -> Result<bool, NodeError> {
901 Ok(applier.get_mut(root)?.needs_semantics())
902}
903
904#[cfg(test)]
905pub(crate) fn bubble_layout_dirty(applier: &mut MemoryApplier, node_id: NodeId) {
906 cranpose_core::bubble_layout_dirty(applier as &mut dyn Applier, node_id);
907}
908
909pub fn measure_layout(
911 applier: &mut MemoryApplier,
912 root: NodeId,
913 max_size: Size,
914) -> Result<LayoutMeasurements, NodeError> {
915 measure_layout_with_options(applier, root, max_size, MeasureLayoutOptions::default())
916}
917
918pub fn measure_layout_with_options(
921 applier: &mut MemoryApplier,
922 root: NodeId,
923 max_size: Size,
924 options: MeasureLayoutOptions,
925) -> Result<LayoutMeasurements, NodeError> {
926 let mut stages = LayoutStages::start(layout_measure_telemetry_threshold_ms().is_some());
927 let context = crate::render_state::require_current_app_context("a layout pass");
928 context.begin_text_layout_pass();
929 context.placement_pass().begin();
930 process_pending_layout_repasses(&context, applier, root)?;
931 stages.reached();
932
933 let constraints = Constraints {
934 min_width: 0.0,
935 max_width: max_size.width,
936 min_height: 0.0,
937 max_height: max_size.height,
938 };
939
940 let (needs_remeasure, _needs_semantics, cached_epoch) = match applier
941 .with_node::<LayoutNode, _>(root, |node| {
942 (
943 node.needs_measure() || Node::descendant_needs_measure(node),
944 node.needs_semantics(),
945 node.cache().epoch(),
946 )
947 }) {
948 Ok(tuple) => tuple,
949 Err(NodeError::TypeMismatch { .. }) => {
950 let node = applier.get_mut(root)?;
951 let measure_dirty = node.needs_measure() || node.descendant_needs_measure();
952 let semantics_dirty = node.needs_semantics();
953 (measure_dirty, semantics_dirty, 0)
954 }
955 Err(err) => return Err(err),
956 };
957
958 let epoch = if needs_remeasure {
959 context.next_layout_cache_epoch()
960 } else if cached_epoch != 0 {
961 cached_epoch
962 } else {
963 context.current_layout_cache_epoch()
964 };
965
966 let guard = ApplierSlotGuard::new(applier, &context);
967 let applier_host = guard.host();
968 stages.reached();
969
970 let builder = LayoutBuilder::new_with_epoch(Rc::clone(applier_host), epoch, &context);
971 stages.reached();
972
973 let measured = builder
974 .state
975 .measure_root(root, normalize_constraints(constraints))?;
976 stages.reached();
977
978 if let Ok(mut applier) = applier_host.try_borrow_typed() {
979 finish_placement(&mut applier, root, &context);
980 }
981 stages.reached();
982
983 let (layout_tree, semantics) = {
984 let mut applier_ref = applier_host.borrow_typed();
985 let layout_tree = if options.build_layout_tree {
986 Some(build_layout_tree(&mut applier_ref, &measured)?)
987 } else {
988 None
989 };
990 let semantics = if options.collect_semantics {
991 let semantics_tree = if let Some(layout_tree) = layout_tree.as_ref() {
992 clear_semantics_dirty_flags(&mut applier_ref, &measured)?;
993 build_semantics_tree_from_layout_tree(layout_tree)
994 } else {
995 build_semantics_tree_from_live_nodes(&mut applier_ref, &measured)?
996 };
997 Some(semantics_tree)
998 } else {
999 None
1000 };
1001 (layout_tree, semantics)
1002 };
1003 stages.reached();
1004
1005 drop(builder);
1006 stages.reached();
1007
1008 drop(guard);
1009 stages.reached();
1010
1011 log_layout_measure_telemetry(root, &stages);
1012
1013 Ok(LayoutMeasurements::new(measured, semantics, layout_tree))
1014}
1015
1016fn process_pending_layout_repasses(
1017 context: &AppContext,
1018 applier: &mut MemoryApplier,
1019 root: NodeId,
1020) -> Result<(), NodeError> {
1021 for node_id in context.take_modifier_slice_repass_nodes() {
1022 if let Ok(node) = applier.get_mut(node_id) {
1023 let any = node.as_any_mut();
1024 if let Some(layout) = any.downcast_mut::<LayoutNode>() {
1025 layout.mark_modifier_slices_dirty();
1026 } else if let Some(subcompose) = any.downcast_mut::<SubcomposeLayoutNode>() {
1027 subcompose.mark_modifier_slices_dirty();
1028 }
1029 }
1030 }
1031 let measure_repass_nodes = context.take_measure_repass_nodes();
1032 let repass_nodes = context.take_layout_repass_nodes();
1033 if measure_repass_nodes.is_empty() && repass_nodes.is_empty() {
1034 return Ok(());
1035 }
1036 for node_id in measure_repass_nodes {
1037 cranpose_core::bubble_measure_dirty(applier as &mut dyn Applier, node_id);
1038 }
1039 for node_id in repass_nodes {
1040 cranpose_core::bubble_layout_dirty(applier as &mut dyn Applier, node_id);
1041 }
1042 applier.get_mut(root)?.mark_descendant_needs_layout(false);
1043 Ok(())
1044}
1045
1046struct LayoutBuilder<'a> {
1049 state: Rc<LayoutBuilderState>,
1050 context: &'a AppContext,
1051}
1052
1053impl<'a> LayoutBuilder<'a> {
1054 fn new_with_epoch(
1055 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1056 epoch: u64,
1057 context: &'a Rc<AppContext>,
1058 ) -> Self {
1059 Self {
1060 state: Rc::new(LayoutBuilderState::new_with_epoch(
1061 applier,
1062 epoch,
1063 Rc::clone(context),
1064 )),
1065 context,
1066 }
1067 }
1068}
1069
1070impl Drop for LayoutBuilder<'_> {
1071 fn drop(&mut self) {
1072 if Rc::strong_count(&self.state) != 1 {
1073 return;
1074 }
1075 let Ok(mut frame_arena) = self.state.frame_arena.try_borrow_mut() else {
1076 return;
1077 };
1078 self.context
1079 .replace_layout_frame_arena(std::mem::take(&mut *frame_arena));
1080 }
1081}
1082
1083struct LayoutBuilderState {
1084 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1085 runtime_handle: RefCell<Option<RuntimeHandle>>,
1086 cache_epoch: u64,
1087 cache_floor: u64,
1088 frame_arena: RefCell<FrameLayoutArena>,
1089 context: Rc<AppContext>,
1092 measure_telemetry_ms: Option<f64>,
1095}
1096
1097struct LayoutRuntimeFrameBindingCleanup<'a> {
1098 state: &'a RefCell<LayoutRuntimeState>,
1099}
1100
1101impl Drop for LayoutRuntimeFrameBindingCleanup<'_> {
1102 fn drop(&mut self) {
1103 self.state.borrow().unbind_children();
1104 }
1105}
1106
1107enum LayoutNodeVisit<'a> {
1108 Cached(Rc<MeasuredNode>),
1109 Keep(KeptNode),
1112 Measure(LayoutNodeMeasure<'a>),
1113}
1114
1115struct KeptNode {
1118 measured: Rc<MeasuredNode>,
1119 parts: Rc<LayoutParts>,
1120 ignores_child_sizes: bool,
1123}
1124
1125struct KeptChildren {
1128 measured: Rc<MeasuredNode>,
1129 resized: bool,
1130}
1131
1132#[derive(Clone, Copy)]
1134struct ChangedChild {
1135 constraints: Constraints,
1136 placed: bool,
1137}
1138
1139enum ChildChange {
1141 Unchanged,
1142 Changed(ChangedChild),
1143 Refuse,
1145}
1146
1147struct ChildView {
1150 self_dirty: bool,
1151 parent_data: Option<cranpose_ui_layout::ParentData>,
1154 cached_constraints: Option<Constraints>,
1156 read_intrinsics: bool,
1157 placed: bool,
1158}
1159
1160impl ChildView {
1161 fn of(node: &LiveLayoutNode<'_>) -> Option<Self> {
1163 let cache = node.cache();
1164 let dirt = cache.dirt();
1165 let self_dirty = dirt.measure || dirt.layout;
1166 if !self_dirty && !dirt.descendant.layout {
1167 return None;
1168 }
1169 Some(Self {
1170 self_dirty,
1171 parent_data: self_dirty.then(|| node.parent_data()),
1172 cached_constraints: cache.measured_constraints(),
1173 read_intrinsics: cache.has_intrinsics(),
1174 placed: node.is_placed(),
1175 })
1176 }
1177}
1178
1179struct LayoutNodeMeasure<'a> {
1180 parts: Rc<LayoutParts>,
1181 chain: ModifierChainInputs,
1182 pools: VecPools<'a>,
1183 spare: MeasuredSpare,
1184}
1185
1186#[expect(clippy::multiple_inherent_impl, reason = "bottom-up pass in its file")]
1187impl LayoutBuilderState {
1188 fn new_with_epoch(
1189 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1190 epoch: u64,
1191 context: Rc<AppContext>,
1192 ) -> Self {
1193 let runtime_handle = applier.borrow_typed().runtime_handle();
1194
1195 Self {
1196 applier,
1197 runtime_handle: RefCell::new(runtime_handle),
1198 cache_epoch: epoch,
1199 cache_floor: context.layout_cache_floor(),
1200 frame_arena: RefCell::new(context.take_layout_frame_arena()),
1201 context,
1202 measure_telemetry_ms: layout_measure_telemetry_threshold_ms(),
1203 }
1204 }
1205
1206 fn with_applier_result<R>(
1207 &self,
1208 f: impl FnOnce(&mut MemoryApplier) -> Result<R, NodeError>,
1209 ) -> Result<R, NodeError> {
1210 let Ok(mut applier) = self.applier.try_borrow_typed() else {
1211 return Err(NodeError::MissingContext {
1212 id: NodeId::default(),
1213 reason: "applier already borrowed",
1214 });
1215 };
1216 f(&mut applier)
1217 }
1218
1219 fn measure_subcompose_node(
1220 self: &Rc<Self>,
1221 node_id: NodeId,
1222 constraints: Constraints,
1223 ) -> Result<(&'static str, Rc<MeasuredNode>), NodeError> {
1224 self.clear_subcompose_placed(node_id);
1225 if let Some(cached) = self.subcompose_measurement_to_keep(node_id, constraints)
1226 && let Some(kept) = self.keep_subcompose_measurement(node_id, constraints, &cached)?
1227 {
1228 return Ok(("subcompose kept", kept));
1229 }
1230 Ok(match self.try_measure_subcompose(node_id, constraints)? {
1231 Some(measured) => {
1232 self.store_subcompose_measurement(node_id, constraints, &measured);
1233 ("subcompose", measured)
1234 }
1235 None => (
1236 "fallback",
1237 Rc::new(MeasuredNode::new(
1238 node_id,
1239 Size::default(),
1240 Point { x: 0.0, y: 0.0 },
1241 Point::default(),
1242 Vec::new(),
1243 )),
1244 ),
1245 })
1246 }
1247
1248 fn subcompose_measurement_to_keep(
1252 &self,
1253 node_id: NodeId,
1254 constraints: Constraints,
1255 ) -> Option<Rc<MeasuredNode>> {
1256 let mut applier = self.applier.try_borrow_typed().ok()?;
1257 applier
1258 .with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1259 if node.needs_measure() || Node::needs_layout(node) {
1260 return None;
1261 }
1262 let cache = node.cache();
1263 if cache.epoch() < self.cache_floor {
1264 return None;
1265 }
1266 cache.get_measurement(constraints)
1267 })
1268 .ok()
1269 .flatten()
1270 }
1271
1272 fn keep_subcompose_measurement(
1278 self: &Rc<Self>,
1279 node_id: NodeId,
1280 constraints: Constraints,
1281 cached: &Rc<MeasuredNode>,
1282 ) -> Result<Option<Rc<MeasuredNode>>, NodeError> {
1283 let kept = self.remeasure_changed_children(
1284 cached,
1285 false,
1286 |child_id| self.subcompose_child_change(child_id),
1287 |child_id| self.mark_measured_without_policy(child_id),
1288 )?;
1289 let Some(KeptChildren { measured: kept, .. }) = kept else {
1290 return Ok(None);
1291 };
1292 self.with_applier_result(|applier| {
1293 applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1294 node.cache()
1295 .store_measurement(constraints, Rc::clone(&kept));
1296 node.clear_needs_layout();
1297 })
1298 })?;
1299 Ok(Some(kept))
1300 }
1301
1302 fn subcompose_child_change(&self, child_id: NodeId) -> Result<ChildChange, NodeError> {
1306 self.child_change(child_id, |view| {
1307 match view.cached_constraints.filter(|_| !view.self_dirty) {
1308 Some(constraints) if !view.read_intrinsics => ChildChange::Changed(ChangedChild {
1309 constraints,
1310 placed: view.placed,
1311 }),
1312 _ => ChildChange::Refuse,
1313 }
1314 })
1315 }
1316
1317 fn child_change(
1320 &self,
1321 child_id: NodeId,
1322 decide: impl FnOnce(ChildView) -> ChildChange,
1323 ) -> Result<ChildChange, NodeError> {
1324 let Ok(mut applier) = self.applier.try_borrow_typed() else {
1325 return Ok(ChildChange::Refuse);
1326 };
1327 Ok(
1328 match read_live_layout_node(&mut applier, child_id, |node| ChildView::of(&node))? {
1329 None => ChildChange::Refuse,
1330 Some(None) => ChildChange::Unchanged,
1331 Some(Some(view)) => decide(view),
1332 },
1333 )
1334 }
1335
1336 fn mark_measured_without_policy(&self, child_id: NodeId) {
1340 let Ok(mut applier) = self.applier.try_borrow_typed() else {
1341 return;
1342 };
1343 if let Ok(node) = applier.get_mut(child_id) {
1344 node.mark_descendant_needs_layout(true);
1345 }
1346 }
1347
1348 fn clear_subcompose_placed(&self, node_id: NodeId) {
1349 let Ok(mut applier) = self.applier.try_borrow_typed() else {
1350 return;
1351 };
1352 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1353 node.clear_placed(&self.context);
1354 });
1355 }
1356
1357 fn measure_node(
1358 self: &Rc<Self>,
1359 node_id: NodeId,
1360 constraints: Constraints,
1361 ) -> Result<Rc<MeasuredNode>, NodeError> {
1362 let Some(threshold_ms) = self.measure_telemetry_ms else {
1363 return self
1364 .measure_node_untimed(node_id, constraints)
1365 .map(|(_, measured)| measured);
1366 };
1367 self.measure_node_timed(node_id, constraints, threshold_ms)
1368 }
1369
1370 #[inline(never)]
1373 fn measure_node_timed(
1374 self: &Rc<Self>,
1375 node_id: NodeId,
1376 constraints: Constraints,
1377 threshold_ms: f64,
1378 ) -> Result<Rc<MeasuredNode>, NodeError> {
1379 let start = Instant::now();
1380 let (kind, measured) = self.measure_node_untimed(node_id, constraints)?;
1381 log_node_measure_telemetry(kind, node_id, constraints, &measured, (threshold_ms, start));
1382 Ok(measured)
1383 }
1384
1385 fn measure_node_untimed(
1387 self: &Rc<Self>,
1388 node_id: NodeId,
1389 constraints: Constraints,
1390 ) -> Result<(&'static str, Rc<MeasuredNode>), NodeError> {
1391 if let Some(measured) = self.measure_layout_node(node_id, constraints)? {
1392 return Ok(("layout", measured));
1393 }
1394 self.measure_subcompose_node(node_id, constraints)
1395 }
1396
1397 fn try_measure_subcompose(
1398 self: &Rc<Self>,
1399 node_id: NodeId,
1400 constraints: Constraints,
1401 ) -> Result<Option<Rc<MeasuredNode>>, NodeError> {
1402 let (node_handle, resolved_modifiers, spare) = {
1403 let Ok(mut applier) = self.applier.try_borrow_typed() else {
1404 return Ok(None);
1405 };
1406 let node = match applier.get_mut(node_id) {
1407 Ok(node) => node,
1408 Err(NodeError::Missing { .. }) => return Ok(None),
1409 Err(err) => return Err(err),
1410 };
1411 let any = node.as_any_mut();
1412 if let Some(subcompose) = any.downcast_mut::<SubcomposeLayoutNode>() {
1413 let handle = subcompose.handle();
1414 let resolved_modifiers = handle
1415 .resolved_modifiers()
1416 .on_device_grid(subcompose.density().density());
1417 let spare = MeasuredSpare::take(subcompose.cache());
1418 (handle, resolved_modifiers, spare)
1419 } else {
1420 return Ok(None);
1421 }
1422 };
1423
1424 let props = resolved_modifiers.layout_properties();
1425 let padding = resolved_modifiers.padding();
1426 let offset = resolved_modifiers.offset();
1427 let mut inner_constraints = normalize_constraints(subtract_padding(constraints, padding));
1428
1429 if let DimensionConstraint::Points(width) = props.width() {
1430 let constrained_width = width - padding.horizontal_sum();
1431 inner_constraints.max_width = inner_constraints.max_width.min(constrained_width);
1432 inner_constraints.min_width = inner_constraints.min_width.min(constrained_width);
1433 }
1434 if let DimensionConstraint::Points(height) = props.height() {
1435 let constrained_height = height - padding.vertical_sum();
1436 inner_constraints.max_height = inner_constraints.max_height.min(constrained_height);
1437 inner_constraints.min_height = inner_constraints.min_height.min(constrained_height);
1438 }
1439
1440 let measure_error = RefCell::new(None);
1441 let measured_children = node_handle.measured_children_scratch();
1442 let measure_result = self.subcompose_policy_result(
1443 &node_handle,
1444 node_id,
1445 inner_constraints,
1446 &measured_children,
1447 &measure_error,
1448 )?;
1449
1450 if let Some(err) = measure_error.borrow_mut().take() {
1451 return Err(err);
1452 }
1453
1454 let cranpose_ui_layout::MeasureResult {
1455 size: measured_size,
1456 alignment_lines: explicit_lines,
1457 placements,
1458 } = measure_result;
1459
1460 let mut width = measured_size.width + padding.horizontal_sum();
1461 let mut height = measured_size.height + padding.vertical_sum();
1462
1463 width = resolve_dimension(
1464 width,
1465 props.width(),
1466 props.min_width(),
1467 props.max_width(),
1468 constraints.min_width,
1469 constraints.max_width,
1470 );
1471 height = resolve_dimension(
1472 height,
1473 props.height(),
1474 props.min_height(),
1475 props.max_height(),
1476 constraints.min_height,
1477 constraints.max_height,
1478 );
1479
1480 let MeasuredSpare {
1481 node: spare,
1482 mut children,
1483 } = spare;
1484 children.reserve_exact(placements.len());
1485 let mut alignment_lines = AlignmentLines::default();
1486 let mut measured_children_by_id = measured_children.borrow_mut();
1487
1488 let mut applier = self.applier.try_borrow_typed().ok();
1491 if let Some(applier) = applier.as_mut() {
1492 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |parent_node| {
1493 parent_node.set_measured_size(Size { width, height }, &self.context);
1494 parent_node.clear_needs_measure();
1495 parent_node.clear_needs_layout();
1496 });
1497 }
1498
1499 let placed_roots = node_handle.take_placed_roots();
1502 let mut carried = PlacedRootMeasurements::new(&placed_roots);
1503 for placement in &placements {
1504 let looked_up;
1505 let child: &MeasuredNode = if let Some(measured) = carried.next_measurement() {
1506 measured
1507 } else {
1508 looked_up =
1509 if let Some(measured) = measured_children_by_id.remove(&placement.node_id) {
1510 measured
1511 } else {
1512 drop(applier.take());
1513 let measured = self.measure_node(placement.node_id, inner_constraints)?;
1514 applier = self.applier.try_borrow_typed().ok();
1515 measured
1516 };
1517 &looked_up
1518 };
1519 let policy_position = Point {
1520 x: padding.left + placement.x,
1521 y: padding.top + placement.y,
1522 };
1523 let retained_position = Point {
1524 x: policy_position.x + child.offset.x,
1525 y: policy_position.y + child.offset.y,
1526 };
1527 alignment_lines.merge(
1528 child
1529 .alignment_lines_for_parent()
1530 .translated(policy_position.y),
1531 );
1532
1533 if let Some(applier) = applier.as_mut()
1534 && applier
1535 .with_node::<LayoutNode, _>(placement.node_id, |node| {
1536 node.set_position(retained_position, Some(node_id), &self.context);
1537 })
1538 .is_err()
1539 {
1540 let _ = applier.with_node::<SubcomposeLayoutNode, _>(placement.node_id, |node| {
1541 node.set_position(retained_position, Some(node_id), &self.context);
1542 });
1543 }
1544
1545 children.push(MeasuredChild::new(child, policy_position));
1546 }
1547 drop(applier);
1548
1549 node_handle.recycle_placed_roots(placed_roots);
1550 node_handle.recycle_placement_scratch(placements);
1551
1552 Ok(Some(
1553 MeasuredNode::new(
1554 node_id,
1555 Size { width, height },
1556 offset,
1557 Point::default(),
1558 children,
1559 )
1560 .with_alignment_lines(
1561 alignment_lines
1562 .with_overrides(explicit_lines.translated(padding.top))
1563 .translated(offset.y),
1564 )
1565 .into_rc(spare),
1566 ))
1567 }
1568
1569 fn subcompose_policy_result(
1574 self: &Rc<Self>,
1575 node_handle: &SubcomposeLayoutNodeHandle,
1576 node_id: NodeId,
1577 constraints: Constraints,
1578 measured_children: &MeasuredChildren,
1579 measure_error: &RefCell<Option<NodeError>>,
1580 ) -> Result<cranpose_ui_layout::MeasureResult, NodeError> {
1581 let applier_host: Rc<dyn ApplierHost> = Rc::clone(&self.applier) as Rc<dyn ApplierHost>;
1582 if let Some(result) = node_handle.measure_retained(&*applier_host, node_id, constraints) {
1583 return Ok(result);
1584 }
1585 let runtime_handle = {
1586 let mut runtime_handle = self.runtime_handle.borrow_mut();
1587 if runtime_handle.is_none()
1588 && let Ok(applier) = self.applier.try_borrow_typed()
1589 {
1590 *runtime_handle = applier.runtime_handle();
1591 }
1592 runtime_handle.clone().ok_or(NodeError::MissingContext {
1593 id: node_id,
1594 reason: "runtime handle required for subcomposition",
1595 })?
1596 };
1597 node_handle.measure_with_callbacks(
1598 &applier_host,
1599 &runtime_handle,
1600 node_id,
1601 constraints,
1602 MeasureCallbacks {
1603 measurer: Box::new(|child_id: NodeId, child_constraints: Constraints| {
1604 match self.measure_node(child_id, child_constraints) {
1605 Ok(measured) => {
1606 measured_children
1607 .borrow_mut()
1608 .insert(child_id, Rc::clone(&measured));
1609 let size = measured.size_for_parent();
1610 Placeable::value(size.width, size.height, child_id)
1611 .with_alignment_lines(measured.alignment_lines_for_parent())
1612 }
1613 Err(err) => {
1614 let mut slot = measure_error.borrow_mut();
1615 if slot.is_none() {
1616 *slot = Some(err);
1617 }
1618 Placeable::value(0.0, 0.0, child_id)
1619 }
1620 }
1621 }),
1622 retained_measure_lookup: Box::new(|child_id| {
1623 measured_children.borrow().get(&child_id).cloned()
1624 }),
1625 error: measure_error,
1626 },
1627 )
1628 }
1629
1630 fn measure_layout_node(
1631 self: &Rc<Self>,
1632 node_id: NodeId,
1633 constraints: Constraints,
1634 ) -> Result<Option<Rc<MeasuredNode>>, NodeError> {
1635 let mut keep = true;
1636 let (mut applier, measure) = loop {
1637 let Ok(mut applier) = self.applier.try_borrow_typed() else {
1638 return Ok(None);
1639 };
1640 match applier.with_node::<LayoutNode, _>(node_id, |node| {
1641 self.visit_layout_node(node, constraints, keep)
1642 }) {
1643 Ok(LayoutNodeVisit::Measure(measure)) => break (applier, measure),
1644 Ok(LayoutNodeVisit::Cached(measured)) => return Ok(Some(measured)),
1645 Ok(LayoutNodeVisit::Keep(node)) => {
1646 drop(applier);
1647 if let Some(kept) = self.keep_measurement(constraints, node)? {
1648 return Ok(Some(kept));
1649 }
1650 keep = false;
1651 }
1652 Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => return Ok(None),
1653 Err(err) => return Err(err),
1654 }
1655 };
1656 let LayoutNodeMeasure {
1657 parts,
1658 chain,
1659 mut pools,
1660 spare,
1661 } = measure;
1662
1663 let _frame_binding_cleanup = LayoutRuntimeFrameBindingCleanup {
1664 state: parts.runtime_state(),
1665 };
1666 self.bind_layout_children(
1667 &mut applier,
1668 (node_id, parts.runtime_state()),
1669 &pools.child_ids,
1670 ChildPass::Measure,
1671 )?;
1672 drop(applier);
1673
1674 let runtime_state = parts.runtime_state().borrow();
1675 let measurement = self.measure_through_modifier_chain(
1676 node_id,
1677 &runtime_state,
1678 chain,
1679 constraints,
1680 &mut pools.placements,
1681 &mut pools.placement_indices,
1682 );
1683
1684 if let Some(err) = runtime_state.take_child_error() {
1685 for child_state in runtime_state.child_states() {
1686 child_state.measured.take();
1687 }
1688 self.with_applier_result(|applier| {
1689 applier.with_node::<LayoutNode, _>(node_id, |node| {
1690 if runtime_state.take_moved_coordinators() {
1691 node.note_geometry_change(node_id, &self.context);
1692 }
1693 })
1694 })
1695 .ok();
1696 return Err(err);
1697 }
1698
1699 let MeasuredSpare {
1700 node: spare,
1701 mut children,
1702 } = spare;
1703 runtime_state.measured_children(
1704 &pools.placements,
1705 &pools.placement_indices,
1706 measurement.content_offset,
1707 &mut children,
1708 );
1709 let measured = MeasuredNode::new(
1710 node_id,
1711 measurement.size,
1712 measurement.offset,
1713 measurement.content_offset,
1714 children,
1715 )
1716 .with_alignment_lines(measurement.alignment_lines)
1717 .with_window_root(measurement.window_root)
1718 .into_rc(spare);
1719
1720 self.with_applier_result(|applier| {
1721 applier.with_node::<LayoutNode, _>(node_id, |node| {
1722 node.cache().store_held_measurement(
1723 constraints,
1724 Rc::clone(&measured),
1725 measurement.hold,
1726 measurement.ignores_child_sizes,
1727 );
1728 if runtime_state.take_moved_coordinators() {
1729 node.note_geometry_change(node_id, &self.context);
1730 }
1731 node.clear_needs_measure();
1732 node.clear_needs_layout();
1733 node.set_measured_size(measurement.size, &self.context);
1734 node.set_content_offset(measurement.content_offset);
1735 })
1736 })
1737 .ok();
1738
1739 Ok(Some(measured))
1740 }
1741
1742 fn layout_node_intrinsic(
1747 self: &Rc<Self>,
1748 node_id: NodeId,
1749 kind: IntrinsicKind,
1750 ) -> Result<Option<f32>, NodeError> {
1751 let Ok(mut applier) = self.applier.try_borrow_typed() else {
1752 return Ok(None);
1753 };
1754 let mut pools = VecPools::acquire(&self.frame_arena);
1755 let bound = applier.with_node::<LayoutNode, _>(node_id, |node| {
1756 let parts = Rc::clone(node.layout_parts());
1757 let chain = parts.runtime_state().borrow_mut().bind_node(node);
1758 pools.child_ids.extend_from_slice(&node.children);
1759 (parts, chain)
1760 });
1761 let (parts, chain) = match bound {
1762 Ok(bound) => bound,
1763 Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => return Ok(None),
1764 Err(err) => return Err(err),
1765 };
1766 let _frame_binding_cleanup = LayoutRuntimeFrameBindingCleanup {
1767 state: parts.runtime_state(),
1768 };
1769 self.bind_layout_children(
1770 &mut applier,
1771 (node_id, parts.runtime_state()),
1772 &pools.child_ids,
1773 ChildPass::Intrinsics,
1774 )?;
1775 drop(applier);
1776
1777 let runtime_state = parts.runtime_state().borrow();
1778 let value = if chain.uses_chain {
1779 let scope = crate::density::DensityMeasureScope::new(chain.density);
1780 let frame = CoordinatorFrame::new(
1781 &runtime_state.measure_policy,
1782 &scope,
1783 runtime_state.child_measurables(),
1784 runtime_state.child_states(),
1785 &mut pools.placements,
1786 &mut pools.placement_indices,
1787 );
1788 runtime_state
1789 .coordinator_chain
1790 .intrinsic_from(0, &frame, kind)
1791 } else {
1792 policy_intrinsic(
1793 runtime_state.measure_policy.as_ref(),
1794 runtime_state.child_measurables(),
1795 kind,
1796 )
1797 };
1798 match runtime_state.take_child_error() {
1799 Some(err) => Err(err),
1800 None => Ok(Some(value)),
1801 }
1802 }
1803
1804 fn measurement_to_keep(
1807 &self,
1808 node: &LayoutNode,
1809 constraints: Constraints,
1810 ) -> Option<Rc<MeasuredNode>> {
1811 if node.needs_measure() || node.needs_layout() || node.is_virtual() {
1812 return None;
1813 }
1814 let cache = node.cache();
1815 if cache.epoch() < self.cache_floor {
1816 return None;
1817 }
1818 cache.get_measurement(constraints)
1819 }
1820
1821 #[inline(never)]
1826 fn keep_measurement(
1827 self: &Rc<Self>,
1828 constraints: Constraints,
1829 node: KeptNode,
1830 ) -> Result<Option<Rc<MeasuredNode>>, NodeError> {
1831 let KeptNode {
1832 measured,
1833 parts,
1834 ignores_child_sizes,
1835 } = node;
1836 let mut next_state = 0;
1837 let kept = self.remeasure_changed_children(
1838 &measured,
1839 ignores_child_sizes,
1840 |child_id| self.layout_child_change(parts.runtime_state(), &mut next_state, child_id),
1841 |_| {},
1842 )?;
1843 let Some(KeptChildren {
1844 measured: kept,
1845 resized,
1846 }) = kept
1847 else {
1848 return Ok(None);
1849 };
1850 let cache = parts.cache();
1851 if resized {
1852 cache.store_resized_measurement(constraints, Rc::clone(&kept));
1853 } else {
1854 cache.store_measurement(constraints, Rc::clone(&kept));
1855 }
1856 cache.clear_layout_dirt();
1857 Ok(Some(kept))
1858 }
1859
1860 fn remeasure_changed_children(
1867 self: &Rc<Self>,
1868 cached: &Rc<MeasuredNode>,
1869 ignores_child_sizes: bool,
1870 mut change: impl FnMut(NodeId) -> Result<ChildChange, NodeError>,
1871 mut remeasured: impl FnMut(NodeId),
1872 ) -> Result<Option<KeptChildren>, NodeError> {
1873 let mut resized = false;
1874 for previous in &cached.children {
1875 let child = match change(previous.node_id)? {
1876 ChildChange::Unchanged => continue,
1877 ChildChange::Refuse => return Ok(None),
1878 ChildChange::Changed(child) => child,
1879 };
1880 let measured = self.measure_node(previous.node_id, child.constraints)?;
1881 remeasured(previous.node_id);
1882 let now = ForParent::of(&measured);
1883 if !previous.for_parent.same_as(&now) {
1884 if !(ignores_child_sizes && previous.for_parent.same_but_size(&now)) {
1885 return Ok(None);
1886 }
1887 resized = true;
1888 }
1889 if child.placed {
1890 self.place_where_it_was(cached.node_id, previous.node_id);
1891 }
1892 }
1893 Ok(Some(KeptChildren {
1894 measured: Rc::clone(cached),
1895 resized,
1896 }))
1897 }
1898
1899 fn layout_child_change(
1904 &self,
1905 runtime_state: &RefCell<LayoutRuntimeState>,
1906 next_state: &mut usize,
1907 child_id: NodeId,
1908 ) -> Result<ChildChange, NodeError> {
1909 let runtime_state = runtime_state.borrow();
1910 let Some((offset, state)) = runtime_state
1911 .child_states()
1912 .get(*next_state..)
1913 .unwrap_or_default()
1914 .iter()
1915 .enumerate()
1916 .find(|(_, state)| state.node_id == child_id)
1917 else {
1918 return Ok(ChildChange::Refuse);
1919 };
1920 *next_state += offset + 1;
1921 if read_cell(&state.parts, |parts| {
1923 parts
1924 .as_ref()
1925 .is_some_and(|parts| !parts.cache().dirt().any())
1926 }) {
1927 return Ok(ChildChange::Unchanged);
1928 }
1929 self.child_change(child_id, |view| {
1930 let parent_data_changed = view.parent_data.as_ref().is_some_and(|data| {
1931 read_cell(&state.parent_data, |bound| {
1932 bound.as_ref().is_none_or(|bound| {
1933 runtime_state
1934 .measure_policy
1935 .reads_parent_data_change(bound, data)
1936 })
1937 })
1938 });
1939 match state.measured_constraints.get() {
1940 Some(constraints) if !state.read_intrinsics.get() && !parent_data_changed => {
1941 ChildChange::Changed(ChangedChild {
1942 constraints,
1943 placed: view.placed,
1944 })
1945 }
1946 _ => ChildChange::Refuse,
1947 }
1948 })
1949 }
1950
1951 fn store_subcompose_measurement(
1954 &self,
1955 node_id: NodeId,
1956 constraints: Constraints,
1957 measured: &Rc<MeasuredNode>,
1958 ) {
1959 let Ok(mut applier) = self.applier.try_borrow_typed() else {
1960 return;
1961 };
1962 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1963 node.cache()
1964 .store_measurement(constraints, Rc::clone(measured));
1965 });
1966 }
1967
1968 fn place_where_it_was(&self, parent: NodeId, child_id: NodeId) {
1971 let Ok(mut applier) = self.applier.try_borrow_typed() else {
1972 return;
1973 };
1974 let _ = read_live_layout_node(&mut applier, child_id, |child| {
1975 child.stay_placed(parent, &self.context);
1976 });
1977 }
1978
1979 fn visit_layout_node(
1980 &self,
1981 node: &mut LayoutNode,
1982 constraints: Constraints,
1983 keep: bool,
1984 ) -> LayoutNodeVisit<'_> {
1985 node.clear_placed(&self.context);
1986 if keep && let Some(measured) = self.measurement_to_keep(node, constraints) {
1987 return LayoutNodeVisit::Keep(KeptNode {
1988 ignores_child_sizes: node.cache().ignores_child_sizes_of(&measured),
1989 measured,
1990 parts: Rc::clone(node.layout_parts()),
1991 });
1992 }
1993 let cache = node.cache();
1994 cache.activate(self.cache_epoch);
1995 if !Node::layout_dirty(node)
1996 && let Some(cached) = cache.get_measurement(constraints)
1997 {
1998 node.clear_needs_measure();
1999 node.clear_needs_layout();
2000 return LayoutNodeVisit::Cached(cached);
2001 }
2002
2003 let spare = MeasuredSpare::take(cache);
2004 let parts = Rc::clone(node.layout_parts());
2005 let chain = parts.runtime_state().borrow_mut().bind_node(node);
2006 let mut pools = VecPools::acquire(&self.frame_arena);
2007 pools.child_ids.extend_from_slice(&node.children);
2008 LayoutNodeVisit::Measure(LayoutNodeMeasure {
2009 parts,
2010 chain,
2011 pools,
2012 spare,
2013 })
2014 }
2015
2016 fn bind_layout_children(
2017 self: &Rc<Self>,
2018 applier: &mut MemoryApplier,
2019 (node_id, runtime_state): (NodeId, &RefCell<LayoutRuntimeState>),
2020 child_ids: &[NodeId],
2021 pass: ChildPass,
2022 ) -> Result<(), NodeError> {
2023 let mut runtime_state = runtime_state.borrow_mut();
2024 runtime_state.bind_children(self, node_id, pass, child_ids.len());
2025 let mut bound = 0;
2026 for &child_id in child_ids {
2027 if self.bind_layout_child(applier, &mut runtime_state, bound, child_id)? {
2028 bound += 1;
2029 }
2030 }
2031 runtime_state.truncate_children(bound);
2032 Ok(())
2033 }
2034
2035 fn bind_layout_child(
2036 &self,
2037 applier: &mut MemoryApplier,
2038 runtime_state: &mut LayoutRuntimeState,
2039 position: usize,
2040 child_id: NodeId,
2041 ) -> Result<bool, NodeError> {
2042 let bound = applier.with_node::<LayoutNode, _>(child_id, |child| {
2043 runtime_state.child_state_at(position, child_id).bind(
2044 LayoutChildBinding {
2045 parts: child.layout_parts(),
2046 layout_node: true,
2047 parent_data: Some(child.parent_data()),
2048 dirty: child.needs_layout() || child.needs_measure(),
2049 descendant_dirty: Node::descendant_needs_layout(child),
2050 },
2051 self,
2052 );
2053 });
2054 match bound {
2055 Ok(()) => Ok(true),
2056 Err(NodeError::TypeMismatch { .. }) => {
2057 match applier.with_node::<SubcomposeLayoutNode, _>(child_id, |child| {
2058 runtime_state.child_state_at(position, child_id).bind(
2059 LayoutChildBinding {
2060 parts: child.layout_parts(),
2061 layout_node: false,
2062 parent_data: Some(child.parent_data()),
2063 dirty: child.needs_layout() || child.needs_measure(),
2064 descendant_dirty: Node::descendant_needs_layout(child),
2065 },
2066 self,
2067 );
2068 }) {
2069 Ok(()) => Ok(true),
2070 Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => Ok(false),
2071 Err(err) => Err(err),
2072 }
2073 }
2074 Err(NodeError::Missing { .. }) => Ok(false),
2075 Err(err) => Err(err),
2076 }
2077 }
2078
2079 fn measure_through_modifier_chain(
2080 &self,
2081 node_id: NodeId,
2082 runtime_state: &LayoutRuntimeState,
2083 chain: ModifierChainInputs,
2084 constraints: Constraints,
2085 placements: &mut Vec<Placement>,
2086 placement_indices: &mut Vec<usize>,
2087 ) -> ModifierChainMeasurement {
2088 let scope = crate::density::DensityMeasureScope::new(chain.density);
2089
2090 if !chain.uses_chain {
2091 let measurement = runtime_state.measure_policy.measure_into(
2092 &scope,
2093 runtime_state.child_measurables(),
2094 constraints,
2095 placements,
2096 );
2097 return ModifierChainMeasurement {
2098 size: measurement.size,
2099 alignment_lines: inherited_alignment_lines(
2100 runtime_state.child_states(),
2101 placements,
2102 placement_indices,
2103 )
2104 .with_overrides(measurement.alignment_lines),
2105 content_offset: Point::default(),
2106 offset: chain.offset,
2107 window_root: chain.window_root,
2108 hold: if chain.window_root {
2109 None
2110 } else {
2111 runtime_state.measure_policy.measure_hold(
2112 runtime_state.child_measurables(),
2113 constraints,
2114 measurement.size,
2115 )
2116 },
2117 ignores_child_sizes: !chain.window_root
2118 && runtime_state
2119 .measure_policy
2120 .ignores_child_sizes(runtime_state.child_measurables(), constraints),
2121 };
2122 }
2123
2124 let frame = CoordinatorFrame::new(
2125 &runtime_state.measure_policy,
2126 &scope,
2127 runtime_state.child_measurables(),
2128 runtime_state.child_states(),
2129 placements,
2130 placement_indices,
2131 );
2132 let placeable = runtime_state
2133 .coordinator_chain
2134 .measure_from(0, &frame, constraints);
2135 let (content_x, content_y) = placeable.content_offset();
2136
2137 let invalidations = frame.take_invalidations();
2138 if !invalidations.is_empty() {
2139 self.with_applier_result(|applier| {
2140 applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
2141 for kind in invalidations {
2142 match kind {
2143 InvalidationKind::Layout => layout_node.mark_needs_measure(),
2144 InvalidationKind::Draw => layout_node.mark_needs_redraw(),
2145 InvalidationKind::Semantics => layout_node.mark_needs_semantics(),
2146 InvalidationKind::PointerInput => layout_node.mark_needs_pointer_pass(),
2147 InvalidationKind::Focus => layout_node.mark_needs_focus_sync(),
2148 }
2149 }
2150 })
2151 })
2152 .ok();
2153 }
2154
2155 ModifierChainMeasurement {
2156 alignment_lines: placeable.alignment_lines(),
2157 size: Size {
2158 width: placeable.width(),
2159 height: placeable.height(),
2160 },
2161 content_offset: Point {
2162 x: content_x - chain.offset.x,
2163 y: content_y - chain.offset.y,
2164 },
2165 offset: chain.offset,
2166 window_root: chain.window_root,
2167 hold: if chain.window_root {
2168 None
2169 } else {
2170 runtime_state.coordinator_chain.measured_hold(
2171 cranpose_ui_layout::MeasureScope::density(&scope),
2172 runtime_state.measure_policy.as_ref(),
2173 runtime_state.child_measurables(),
2174 )
2175 },
2176 ignores_child_sizes: !chain.window_root
2177 && runtime_state.coordinator_chain.ignores_child_sizes(
2178 runtime_state.measure_policy.as_ref(),
2179 runtime_state.child_measurables(),
2180 ),
2181 }
2182 }
2183}
2184
2185#[derive(Debug, Clone)]
2186pub(crate) struct MeasuredNode {
2187 node_id: NodeId,
2188 size: Size,
2189 offset: Point,
2190 content_offset: Point,
2191 alignment_lines: AlignmentLines,
2192 children: Vec<MeasuredChild>,
2193 window_root: bool,
2194}
2195
2196impl MeasuredNode {
2197 fn new(
2198 node_id: NodeId,
2199 size: Size,
2200 offset: Point,
2201 content_offset: Point,
2202 children: Vec<MeasuredChild>,
2203 ) -> Self {
2204 Self {
2205 node_id,
2206 size,
2207 offset,
2208 content_offset,
2209 alignment_lines: AlignmentLines::default(),
2210 children,
2211 window_root: false,
2212 }
2213 }
2214
2215 fn with_window_root(mut self, window_root: bool) -> Self {
2216 self.window_root = window_root;
2217 self
2218 }
2219
2220 fn with_alignment_lines(mut self, alignment_lines: AlignmentLines) -> Self {
2221 self.alignment_lines = alignment_lines;
2222 self
2223 }
2224
2225 pub(crate) fn alignment_lines_for_parent(&self) -> AlignmentLines {
2226 if self.window_root {
2227 AlignmentLines::default()
2228 } else {
2229 self.alignment_lines
2230 }
2231 }
2232
2233 pub(crate) fn size_for_parent(&self) -> Size {
2234 if self.window_root {
2235 Size::new(0.0, 0.0)
2236 } else {
2237 self.size
2238 }
2239 }
2240
2241 pub(crate) fn size(&self) -> Size {
2242 self.size
2243 }
2244
2245 fn into_rc(self, spare: Option<Rc<Self>>) -> Rc<Self> {
2248 let Some(mut spare) = spare else {
2249 return Rc::new(self);
2250 };
2251 match Rc::get_mut(&mut spare) {
2252 Some(slot) => *slot = self,
2253 None => return Rc::new(self),
2254 }
2255 spare
2256 }
2257}
2258
2259#[derive(Debug, Clone, Copy)]
2264struct MeasuredChild {
2265 node_id: NodeId,
2266 offset: Point,
2267 for_parent: ForParent,
2268}
2269
2270impl MeasuredChild {
2271 fn new(measured: &MeasuredNode, offset: Point) -> Self {
2272 Self {
2273 node_id: measured.node_id,
2274 offset,
2275 for_parent: ForParent::of(measured),
2276 }
2277 }
2278}
2279
2280#[derive(Debug, Clone, Copy)]
2283struct ForParent {
2284 size: Size,
2285 offset: Point,
2286 alignment_lines: AlignmentLines,
2287}
2288
2289impl ForParent {
2290 fn of(measured: &MeasuredNode) -> Self {
2291 Self {
2292 size: measured.size_for_parent(),
2293 offset: measured.offset,
2294 alignment_lines: measured.alignment_lines_for_parent(),
2295 }
2296 }
2297
2298 fn same_as(&self, other: &Self) -> bool {
2301 self.size == other.size && self.same_but_size(other)
2302 }
2303
2304 fn same_but_size(&self, other: &Self) -> bool {
2306 self.offset == other.offset
2307 && self.alignment_lines.first_baseline() == other.alignment_lines.first_baseline()
2308 && self.alignment_lines.last_baseline() == other.alignment_lines.last_baseline()
2309 }
2310}
2311
2312fn policy_intrinsic(
2314 policy: &dyn MeasurePolicy,
2315 measurables: &[Box<dyn Measurable>],
2316 kind: IntrinsicKind,
2317) -> f32 {
2318 match kind {
2319 IntrinsicKind::MinWidth(height) => policy.min_intrinsic_width(measurables, height),
2320 IntrinsicKind::MaxWidth(height) => policy.max_intrinsic_width(measurables, height),
2321 IntrinsicKind::MinHeight(width) => policy.min_intrinsic_height(measurables, width),
2322 IntrinsicKind::MaxHeight(width) => policy.max_intrinsic_height(measurables, width),
2323 }
2324}
2325
2326fn inherited_alignment_lines(
2327 child_states: &[Rc<LayoutChildMeasureState>],
2328 placements: &[Placement],
2329 placement_indices: &mut Vec<usize>,
2330) -> AlignmentLines {
2331 placement_indices.clear();
2332 let in_child_order = placements.len() == child_states.len()
2333 && placements
2334 .iter()
2335 .zip(child_states)
2336 .all(|(placement, child)| placement.node_id == child.node_id);
2337 if !in_child_order {
2338 placement_indices.extend(0..placements.len());
2339 placement_indices.sort_unstable_by_key(|&index| (placements[index].node_id, index));
2340 }
2341 let mut lines = AlignmentLines::default();
2342 for (index, child) in child_states.iter().enumerate() {
2343 let placement = placement_for_child(placements, placement_indices, index, child.node_id);
2344 read_cell(&child.measured, |measured| {
2345 if let Some(measured) = measured {
2346 lines.merge(
2347 measured
2348 .alignment_lines_for_parent()
2349 .translated(child.placement_position(placement).y),
2350 );
2351 }
2352 });
2353 }
2354 lines
2355}
2356
2357fn placement_for_child<'a>(
2358 placements: &'a [Placement],
2359 indices: &[usize],
2360 child_index: usize,
2361 node_id: NodeId,
2362) -> Option<&'a Placement> {
2363 let index = if indices.is_empty() {
2364 child_index
2365 } else {
2366 let first = indices.partition_point(|&index| placements[index].node_id < node_id);
2367 *indices.get(first)?
2368 };
2369 placements
2370 .get(index)
2371 .filter(|placement| placement.node_id == node_id)
2372}
2373
2374pub(crate) struct LayoutRuntimeState {
2375 children: Option<Box<LayoutChildren>>,
2377 coordinator_chain: CoordinatorChain,
2378 measure_policy: Rc<dyn MeasurePolicy>,
2379}
2380
2381struct LayoutChildren {
2383 ids: Vec<NodeId>,
2384 states: Vec<Rc<LayoutChildMeasureState>>,
2385 measurables: Vec<Box<dyn Measurable>>,
2386 frame: Rc<LayoutChildFrame>,
2387}
2388
2389impl LayoutChildren {
2390 fn with_capacity(count: usize) -> Self {
2394 Self {
2395 ids: Vec::with_capacity(count),
2396 states: Vec::with_capacity(count),
2397 measurables: Vec::with_capacity(count),
2398 frame: Rc::default(),
2399 }
2400 }
2401
2402 #[inline(never)]
2405 fn bind_at(&mut self, position: usize, child_id: NodeId) {
2406 let from = match self.ids[position..].iter().position(|&id| id == child_id) {
2407 Some(offset) => position + offset,
2408 None => {
2409 let state = LayoutChildMeasureState::new(child_id, Rc::clone(&self.frame));
2410 self.ids.push(child_id);
2411 self.states.push(Rc::clone(&state));
2412 self.measurables
2413 .push(Box::new(LayoutChildMeasurable::new(state)));
2414 self.ids.len() - 1
2415 }
2416 };
2417 self.ids.swap(position, from);
2418 self.states.swap(position, from);
2419 self.measurables.swap(position, from);
2420 }
2421}
2422
2423impl LayoutRuntimeState {
2424 pub(crate) fn new(measure_policy: Rc<dyn MeasurePolicy>) -> Self {
2425 Self {
2426 children: None,
2427 coordinator_chain: CoordinatorChain::default(),
2428 measure_policy,
2429 }
2430 }
2431
2432 fn bind_node(&mut self, node: &LayoutNode) -> ModifierChainInputs {
2433 if !Rc::ptr_eq(&self.measure_policy, &node.measure_policy) {
2434 self.measure_policy = Rc::clone(&node.measure_policy);
2435 }
2436 self.coordinator_chain.sync(node)
2437 }
2438
2439 fn child_states(&self) -> &[Rc<LayoutChildMeasureState>] {
2440 self.children
2441 .as_deref()
2442 .map_or(&[], |children| children.states.as_slice())
2443 }
2444
2445 fn child_measurables(&self) -> &[Box<dyn Measurable>] {
2446 self.children
2447 .as_deref()
2448 .map_or(&[], |children| children.measurables.as_slice())
2449 }
2450
2451 fn bind_children(
2454 &mut self,
2455 builder: &Rc<LayoutBuilderState>,
2456 parent: NodeId,
2457 pass: ChildPass,
2458 count: usize,
2459 ) {
2460 if count == 0 && self.children.is_none() {
2461 return;
2462 }
2463 self.children
2464 .get_or_insert_with(|| Box::new(LayoutChildren::with_capacity(count)))
2465 .frame
2466 .bind(builder, parent, pass);
2467 }
2468
2469 fn unbind_children(&self) {
2470 if let Some(children) = &self.children {
2471 children.frame.unbind();
2472 }
2473 }
2474
2475 fn take_child_error(&self) -> Option<NodeError> {
2477 self.children
2478 .as_ref()
2479 .and_then(|children| children.frame.error.borrow_mut().take())
2480 }
2481
2482 #[inline]
2485 fn child_state_at(&mut self, position: usize, child_id: NodeId) -> &LayoutChildMeasureState {
2486 let children = self
2487 .children
2488 .get_or_insert_with(|| Box::new(LayoutChildren::with_capacity(position + 1)));
2489 if children.ids.get(position) != Some(&child_id) {
2490 children.bind_at(position, child_id);
2491 }
2492 &children.states[position]
2493 }
2494
2495 fn truncate_children(&mut self, len: usize) {
2496 if let Some(children) = &mut self.children {
2497 children.ids.truncate(len);
2498 children.states.truncate(len);
2499 children.measurables.truncate(len);
2500 }
2501 }
2502
2503 fn measured_children(
2505 &self,
2506 placements: &[Placement],
2507 placement_indices: &[usize],
2508 content_offset: Point,
2509 measured_children: &mut Vec<MeasuredChild>,
2510 ) {
2511 let child_states = self.child_states();
2512 measured_children.reserve_exact(child_states.len());
2513 for (index, child_state) in child_states.iter().enumerate() {
2514 let Some(measured) = child_state.measured.take() else {
2515 continue;
2516 };
2517 let placement =
2518 placement_for_child(placements, placement_indices, index, child_state.node_id);
2519 let base_position = child_state.placement_position(placement);
2520 let position = Point {
2521 x: base_position.x + measured.offset.x,
2522 y: base_position.y + measured.offset.y,
2523 };
2524 if placement.is_some() && child_state.last_position.get() != Some(position) {
2527 child_state.place_retained(position);
2528 }
2529 measured_children.push(MeasuredChild::new(
2530 &measured,
2531 Point {
2532 x: content_offset.x + base_position.x,
2533 y: content_offset.y + base_position.y,
2534 },
2535 ));
2536 }
2537 }
2538
2539 fn take_moved_coordinators(&self) -> bool {
2544 self.coordinator_chain.take_moved()
2545 }
2546
2547 pub(crate) fn placed_coordinator_rect(
2548 &self,
2549 ordinal: usize,
2550 node_size: Size,
2551 ) -> Option<GeometryRect> {
2552 self.coordinator_chain.placed_rect(ordinal, node_size)
2553 }
2554
2555 #[cfg(test)]
2556 pub(crate) fn debug_stats(&self) -> LayoutRuntimeDebugStats {
2557 LayoutRuntimeDebugStats {
2558 child_ids: self
2559 .children
2560 .as_ref()
2561 .map(|children| children.ids.clone())
2562 .unwrap_or_default(),
2563 child_state_ptrs: self
2564 .child_states()
2565 .iter()
2566 .map(|state| Rc::as_ptr(state) as *const () as usize)
2567 .collect(),
2568 child_measurable_ptrs: self
2569 .child_measurables()
2570 .iter()
2571 .map(|measurable| {
2572 measurable.as_ref() as *const dyn Measurable as *const () as usize
2573 })
2574 .collect(),
2575 child_measurable_count: self.child_measurables().len(),
2576 coordinator_node_ptrs: self.coordinator_chain.debug_ptrs(),
2577 coordinator_node_count: self.coordinator_chain.debug_ptrs().len(),
2578 }
2579 }
2580}
2581
2582#[cfg(test)]
2583#[derive(Debug, Clone, PartialEq, Eq)]
2584pub(crate) struct LayoutRuntimeDebugStats {
2585 pub(crate) child_ids: Vec<NodeId>,
2586 pub(crate) child_state_ptrs: Vec<usize>,
2587 pub(crate) child_measurable_ptrs: Vec<usize>,
2588 pub(crate) child_measurable_count: usize,
2589 pub(crate) coordinator_node_ptrs: Vec<usize>,
2590 pub(crate) coordinator_node_count: usize,
2591}
2592
2593#[derive(Default)]
2594struct LayoutChildFrame {
2595 builder: RefCell<Option<Rc<LayoutBuilderState>>>,
2596 error: RefCell<Option<NodeError>>,
2597 pass: Cell<ChildPass>,
2598 parent: Cell<Option<NodeId>>,
2600}
2601
2602#[derive(Clone, Copy, Default, PartialEq, Eq)]
2604enum ChildPass {
2605 #[default]
2608 Measure,
2609 Intrinsics,
2612}
2613
2614impl LayoutChildFrame {
2615 fn bind(&self, builder: &Rc<LayoutBuilderState>, parent: NodeId, pass: ChildPass) {
2616 self.error.borrow_mut().take();
2617 *self.builder.borrow_mut() = Some(Rc::clone(builder));
2618 self.pass.set(pass);
2619 self.parent.set(Some(parent));
2620 }
2621
2622 fn measures(&self) -> bool {
2623 self.pass.get() == ChildPass::Measure
2624 }
2625
2626 fn unbind(&self) {
2627 self.builder.borrow_mut().take();
2628 }
2629
2630 fn record_error(&self, err: NodeError) {
2631 if self.builder.borrow().is_none() {
2632 return;
2633 }
2634 let mut slot = self.error.borrow_mut();
2635 if slot.is_none() {
2636 *slot = Some(err);
2637 }
2638 }
2639}
2640
2641struct LayoutChildBinding<'a> {
2642 parts: &'a Rc<LayoutParts>,
2643 layout_node: bool,
2646 parent_data: Option<cranpose_ui_layout::ParentData>,
2647 dirty: bool,
2649 descendant_dirty: bool,
2651}
2652
2653struct LayoutChildMeasureState {
2657 node_id: NodeId,
2658 frame: Rc<LayoutChildFrame>,
2659 parts: Cell<Option<Rc<LayoutParts>>>,
2661 layout_node: Cell<bool>,
2664 cache_epoch: Cell<PackedU64>,
2665 force_remeasure: Cell<bool>,
2666 parent_data: Cell<Option<cranpose_ui_layout::ParentData>>,
2667 measured_constraints: Cell<Option<Constraints>>,
2669 read_intrinsics: Cell<bool>,
2671 measured: Cell<Option<Rc<MeasuredNode>>>,
2672 last_position: Cell<Option<Point>>,
2673}
2674
2675pub(crate) fn read_cell<T: Default, R>(cell: &Cell<T>, read: impl FnOnce(&T) -> R) -> R {
2678 let value = cell.take();
2679 let result = read(&value);
2680 cell.set(value);
2681 result
2682}
2683
2684impl LayoutChildMeasureState {
2685 fn placement_position(&self, placement: Option<&Placement>) -> Point {
2686 placement
2687 .map(|placement| Point {
2688 x: placement.x,
2689 y: placement.y,
2690 })
2691 .or_else(|| self.last_position.get())
2692 .unwrap_or_default()
2693 }
2694
2695 fn new(node_id: NodeId, frame: Rc<LayoutChildFrame>) -> Rc<Self> {
2696 Rc::new(Self {
2697 node_id,
2698 frame,
2699 parts: Cell::new(None),
2700 layout_node: Cell::new(false),
2701 cache_epoch: Cell::default(),
2702 force_remeasure: Cell::new(true),
2703 parent_data: Cell::new(None),
2704 measured_constraints: Cell::new(None),
2705 read_intrinsics: Cell::new(false),
2706 measured: Cell::new(None),
2707 last_position: Cell::new(None),
2708 })
2709 }
2710
2711 fn bind(&self, binding: LayoutChildBinding<'_>, pass: &LayoutBuilderState) {
2715 let cache = binding.parts.cache();
2716 let child_epoch = cache.epoch();
2717 let stale = binding.dirty || child_epoch < pass.cache_floor;
2718 let cache_epoch = if stale { pass.cache_epoch } else { child_epoch };
2719 cache.activate(cache_epoch);
2720 let parts = self.parts.take();
2721 let shared = parts
2722 .as_ref()
2723 .is_some_and(|current| Rc::ptr_eq(current, binding.parts));
2724 self.parts.set(if shared {
2725 parts
2726 } else {
2727 Some(Rc::clone(binding.parts))
2728 });
2729 self.layout_node.set(binding.layout_node);
2730 self.cache_epoch.set(PackedU64::new(cache_epoch));
2731 self.force_remeasure.set(stale || binding.descendant_dirty);
2732 self.parent_data.set(binding.parent_data);
2733 if self.frame.measures() {
2734 self.measured.take();
2735 self.last_position.set(None);
2736 self.measured_constraints.set(None);
2737 self.read_intrinsics.set(false);
2738 }
2739 }
2740
2741 fn with_pass_layout_state(&self, f: impl FnOnce(&mut LayoutState, &AppContext)) {
2744 if !self.layout_node.get() {
2745 return;
2746 }
2747 let builder = self.frame.builder.borrow();
2748 let Some(builder) = builder.as_ref() else {
2749 return;
2750 };
2751 read_cell(&self.parts, |parts| {
2752 if let Some(parts) = parts {
2753 f(&mut parts.layout_state().borrow_mut(), &builder.context);
2754 }
2755 });
2756 }
2757
2758 fn place_retained(&self, position: Point) {
2759 self.last_position.set(Some(position));
2760 let builder = self.frame.builder.borrow();
2761 let Some(builder) = builder.as_ref() else {
2762 return;
2763 };
2764 read_cell(&self.parts, |parts| {
2765 if let Some(parts) = parts {
2766 parts.layout_state().borrow_mut().place(
2767 position,
2768 self.frame.parent.get(),
2769 &builder.context,
2770 );
2771 }
2772 });
2773 }
2774
2775 fn layout_intrinsic(&self, kind: IntrinsicKind) -> Option<f32> {
2779 let builder = self.frame.builder.borrow();
2780 let builder = builder.as_ref()?;
2781 match builder.layout_node_intrinsic(self.node_id, kind) {
2782 Ok(value) => value,
2783 Err(err) => {
2784 self.frame.record_error(err);
2785 Some(0.0)
2786 }
2787 }
2788 }
2789
2790 fn perform_measure(&self, constraints: Constraints) -> Result<Rc<MeasuredNode>, NodeError> {
2791 let builder = self.frame.builder.borrow();
2792 let builder = builder.as_ref().ok_or(NodeError::MissingContext {
2793 id: self.node_id,
2794 reason: "layout child applier not configured",
2795 })?;
2796 builder.measure_node(self.node_id, constraints)
2797 }
2798
2799 fn measure_cached(&self, constraints: Constraints) -> Option<Rc<MeasuredNode>> {
2800 if self.frame.measures() {
2801 self.measured_constraints.set(Some(constraints));
2802 }
2803 let parts = read_cell(&self.parts, Clone::clone);
2804 let cache = parts.as_deref().map(LayoutParts::cache);
2805 if let Some(cache) = cache {
2806 cache.activate(self.cache_epoch.get().get());
2807 }
2808 if !self.force_remeasure.get()
2809 && let Some(cached) = cache.and_then(|cache| cache.get_measurement(constraints))
2810 {
2811 if self.frame.measures() {
2814 self.with_pass_layout_state(LayoutState::clear_placed);
2815 }
2816 return Some(cached);
2817 }
2818
2819 match self.perform_measure(constraints) {
2820 Ok(measured) => {
2821 self.force_remeasure.set(false);
2822 if let Some(cache) = cache {
2823 cache.store_measurement(constraints, Rc::clone(&measured));
2824 }
2825 Some(measured)
2826 }
2827 Err(err) => {
2828 self.frame.record_error(err);
2829 None
2830 }
2831 }
2832 }
2833}
2834
2835struct LayoutChildMeasurable {
2836 state: Rc<LayoutChildMeasureState>,
2837}
2838
2839impl LayoutChildMeasurable {
2840 fn new(state: Rc<LayoutChildMeasureState>) -> Self {
2841 Self { state }
2842 }
2843
2844 fn resolved_parent_data(&self) -> Option<cranpose_ui_layout::ParentData> {
2845 if self.state.frame.builder.borrow().is_none() {
2846 return None;
2847 }
2848 read_cell(&self.state.parent_data, Clone::clone)
2849 }
2850
2851 fn intrinsic(
2852 &self,
2853 kind: IntrinsicKind,
2854 constraints: Constraints,
2855 extent: fn(Size) -> f32,
2856 ) -> f32 {
2857 let state = &self.state;
2858 if state.frame.measures() {
2859 state.read_intrinsics.set(true);
2860 }
2861 let parts = read_cell(&state.parts, Clone::clone);
2862 let cache = parts.as_deref().map(LayoutParts::cache);
2863 if let Some(cache) = cache {
2864 cache.activate(state.cache_epoch.get().get());
2865 }
2866 if !state.force_remeasure.get()
2867 && let Some(value) = cache.and_then(|cache| cache.get_intrinsic(&kind))
2868 {
2869 return value;
2870 }
2871 let value = match state.layout_intrinsic(kind) {
2872 Some(value) => value,
2873 None => state
2874 .measure_cached(constraints)
2875 .map_or(0.0, |node| extent(node.size_for_parent())),
2876 };
2877 if let Some(cache) = cache {
2878 cache.store_intrinsic(kind, value);
2879 }
2880 value
2881 }
2882}
2883
2884impl PlaceTarget for LayoutChildMeasureState {
2885 fn place(&self, x: f32, y: f32) {
2886 let internal_offset = read_cell(&self.measured, |measured| {
2887 measured
2888 .as_ref()
2889 .map(|measured| measured.offset)
2890 .unwrap_or_default()
2891 });
2892 self.place_retained(Point {
2893 x: x + internal_offset.x,
2894 y: y + internal_offset.y,
2895 });
2896 }
2897}
2898
2899impl Measurable for LayoutChildMeasurable {
2900 fn measured_hold(&self) -> Option<(Size, cranpose_ui_layout::ConstraintsHold)> {
2901 read_cell(&self.state.measured, |measured| {
2902 let measured = measured.as_ref()?;
2903 let hold = read_cell(&self.state.parts, |parts| {
2904 parts.as_ref()?.cache().hold_of(measured)
2905 })?;
2906 Some((measured.size_for_parent(), hold))
2907 })
2908 }
2909
2910 fn measure(&self, constraints: Constraints) -> Placeable {
2911 let state = &self.state;
2912 let measured = state.measure_cached(constraints);
2913 let (measured_size, size_for_parent) = measured.as_ref().map_or(
2914 (
2915 Size {
2916 width: 0.0,
2917 height: 0.0,
2918 },
2919 Size {
2920 width: 0.0,
2921 height: 0.0,
2922 },
2923 ),
2924 |measured| (measured.size, measured.size_for_parent()),
2925 );
2926 state.with_pass_layout_state(|layout_state, context| {
2927 layout_state.set_size(measured_size, context);
2928 });
2929 let alignment_lines = measured
2930 .as_ref()
2931 .map_or_else(AlignmentLines::default, |node| {
2932 node.alignment_lines_for_parent()
2933 });
2934 state.measured.set(measured);
2935
2936 Placeable::with_place_target(
2937 size_for_parent.width,
2938 size_for_parent.height,
2939 state.node_id,
2940 Rc::clone(&self.state) as Rc<dyn PlaceTarget>,
2941 )
2942 .with_alignment_lines(alignment_lines)
2943 }
2944
2945 fn min_intrinsic_width(&self, height: f32) -> f32 {
2946 self.intrinsic(
2947 IntrinsicKind::MinWidth(height),
2948 Constraints {
2949 min_width: 0.0,
2950 max_width: f32::INFINITY,
2951 min_height: height,
2952 max_height: height,
2953 },
2954 |size| size.width,
2955 )
2956 }
2957
2958 fn max_intrinsic_width(&self, height: f32) -> f32 {
2959 self.intrinsic(
2960 IntrinsicKind::MaxWidth(height),
2961 Constraints {
2962 min_width: 0.0,
2963 max_width: f32::INFINITY,
2964 min_height: 0.0,
2965 max_height: height,
2966 },
2967 |size| size.width,
2968 )
2969 }
2970
2971 fn min_intrinsic_height(&self, width: f32) -> f32 {
2972 self.intrinsic(
2973 IntrinsicKind::MinHeight(width),
2974 Constraints {
2975 min_width: width,
2976 max_width: width,
2977 min_height: 0.0,
2978 max_height: f32::INFINITY,
2979 },
2980 |size| size.height,
2981 )
2982 }
2983
2984 fn max_intrinsic_height(&self, width: f32) -> f32 {
2985 self.intrinsic(
2986 IntrinsicKind::MaxHeight(width),
2987 Constraints {
2988 min_width: 0.0,
2989 max_width: width,
2990 min_height: 0.0,
2991 max_height: f32::INFINITY,
2992 },
2993 |size| size.height,
2994 )
2995 }
2996
2997 fn flex_parent_data(&self) -> Option<cranpose_ui_layout::FlexParentData> {
2998 let parent_data = self.resolved_parent_data()?;
2999 if !parent_data.has_weight() {
3000 return None;
3001 }
3002 Some(cranpose_ui_layout::FlexParentData::new(
3003 parent_data.weight,
3004 parent_data.fill,
3005 ))
3006 }
3007
3008 fn parent_data(&self) -> cranpose_ui_layout::ParentData {
3009 self.resolved_parent_data().unwrap_or_default()
3010 }
3011}
3012
3013#[derive(Clone)]
3014struct RuntimeNodeMetadata {
3015 modifier: Modifier,
3016 resolved_modifiers: ResolvedModifiers,
3017 modifier_slices: Rc<ModifierNodeSlices>,
3018 semantics: Option<Rc<SemanticsConfiguration>>,
3019 role: SemanticsRole,
3020 button_handler: Option<Rc<RefCell<dyn FnMut()>>>,
3021}
3022
3023impl Default for RuntimeNodeMetadata {
3024 fn default() -> Self {
3025 Self {
3026 modifier: Modifier::empty(),
3027 resolved_modifiers: ResolvedModifiers::default(),
3028 modifier_slices: Rc::default(),
3029 semantics: None,
3030 role: SemanticsRole::Unknown,
3031 button_handler: None,
3032 }
3033 }
3034}
3035
3036fn role_from_modifier_slices(modifier_slices: &ModifierNodeSlices) -> SemanticsRole {
3037 modifier_slices
3038 .annotated_text()
3039 .map_or(SemanticsRole::Layout, |text| SemanticsRole::Text {
3040 value: SemanticsText(Rc::clone(&text)),
3041 })
3042}
3043
3044fn runtime_metadata_for(
3045 applier: &mut MemoryApplier,
3046 node_id: NodeId,
3047) -> Result<RuntimeNodeMetadata, NodeError> {
3048 if let Ok(meta) = applier.with_node::<LayoutNode, _>(node_id, |layout| {
3049 let modifier = layout.modifier.clone();
3050 let resolved_modifiers = layout.resolved_modifiers();
3051 let modifier_slices = layout.modifier_slices_snapshot();
3052 let role = role_from_modifier_slices(&modifier_slices);
3053
3054 RuntimeNodeMetadata {
3055 modifier,
3056 resolved_modifiers,
3057 modifier_slices,
3058 semantics: layout.semantics_configuration().map(Rc::new),
3059 role,
3060 button_handler: None,
3061 }
3062 }) {
3063 return Ok(meta);
3064 }
3065
3066 if let Ok((modifier, resolved_modifiers, modifier_slices, semantics)) =
3067 applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
3068 (
3069 node.modifier(),
3070 node.resolved_modifiers(),
3071 node.modifier_slices_snapshot(),
3072 node.semantics_configuration().map(Rc::new),
3073 )
3074 })
3075 {
3076 return Ok(RuntimeNodeMetadata {
3077 modifier,
3078 resolved_modifiers,
3079 modifier_slices,
3080 semantics,
3081 role: SemanticsRole::Subcompose,
3082 button_handler: None,
3083 });
3084 }
3085 Ok(RuntimeNodeMetadata::default())
3086}
3087
3088fn visit_child<R>(
3092 applier: &mut MemoryApplier,
3093 child: &MeasuredChild,
3094 visit: impl FnOnce(&mut MemoryApplier, &MeasuredNode) -> R,
3095) -> R {
3096 let held = applier.get_mut(child.node_id).ok().and_then(|node| {
3097 let any = node.as_any_mut();
3098 if let Some(layout) = any.downcast_ref::<LayoutNode>() {
3099 return layout.cache().held_measurement();
3100 }
3101 any.downcast_ref::<SubcomposeLayoutNode>()
3102 .and_then(|subcompose| subcompose.cache().held_measurement())
3103 });
3104 match held {
3105 Some(held) => visit(applier, &held),
3106 None => visit(
3107 applier,
3108 &MeasuredNode::new(
3109 child.node_id,
3110 Size::default(),
3111 Point::default(),
3112 Point::default(),
3113 Vec::new(),
3114 ),
3115 ),
3116 }
3117}
3118
3119fn clear_semantics_dirty_flags(
3120 applier: &mut MemoryApplier,
3121 node: &MeasuredNode,
3122) -> Result<(), NodeError> {
3123 match applier.with_node::<LayoutNode, _>(node.node_id, |layout| {
3124 layout.clear_needs_semantics();
3125 }) {
3126 Ok(()) => {}
3127 Err(NodeError::Missing { .. }) => {}
3128 Err(NodeError::TypeMismatch { .. }) => {
3129 match applier.with_node::<SubcomposeLayoutNode, _>(node.node_id, |subcompose| {
3130 subcompose.clear_needs_semantics();
3131 }) {
3132 Ok(()) | Err(NodeError::Missing { .. } | NodeError::TypeMismatch { .. }) => {}
3133 Err(err) => return Err(err),
3134 }
3135 }
3136 Err(err) => return Err(err),
3137 }
3138
3139 for child in &node.children {
3140 visit_child(applier, child, clear_semantics_dirty_flags)?;
3141 }
3142
3143 Ok(())
3144}
3145
3146fn build_semantics_tree_from_live_nodes(
3147 applier: &mut MemoryApplier,
3148 node: &MeasuredNode,
3149) -> Result<SemanticsTree, NodeError> {
3150 Ok(SemanticsTree::new(build_semantics_node_from_live_nodes(
3151 applier, node, None,
3152 )?))
3153}
3154
3155fn semantics_node_from_parts(
3156 node_id: NodeId,
3157 node_generation: u32,
3158 mut role: SemanticsRole,
3159 config: Option<SemanticsConfiguration>,
3160 children: Vec<SemanticsNode>,
3161 held_details: Option<Box<SemanticsDetails>>,
3162 bounds: GeometryRect,
3163) -> SemanticsNode {
3164 let focusable = crate::focus_dispatch::has_focus_target(node_id);
3165 let mut node = SemanticsNode {
3166 node_id,
3167 bounds,
3168 node_generation,
3169 children,
3170 focusable,
3171 focused: focusable && crate::focus_dispatch::active_focus_target() == Some(node_id),
3172 details: held_details,
3173 ..SemanticsNode::default()
3174 };
3175 let details = match config {
3176 Some(mut config) => {
3177 if config.role == Some(SemanticsWidgetRole::Button) {
3178 role = SemanticsRole::Button;
3179 }
3180 if config.is_activatable() {
3181 node.actions.push(SemanticsAction::Click {
3182 handler: SemanticsCallback::new(node_id),
3183 });
3184 }
3185 let on_click_label = config.on_click_label.take().or_else(|| {
3186 config
3187 .on_click
3188 .as_ref()
3189 .and_then(|action| (!action.label.is_empty()).then(|| action.label.clone()))
3190 });
3191 node.widget_role = config.role;
3192 node.description = config.content_description.take();
3193 node.on_click = config.on_click.take();
3194 node.selected = config.selected;
3195 node.toggled = config.toggled;
3196 node.enabled = config.enabled;
3197 node.hidden = config.hidden;
3198 node.merge_descendants = config.merge_descendants;
3199 node.traversal_index = config.traversal_index;
3200 node.text = config.text.take();
3201 let is_modal = config.is_modal
3202 && modal_takes_space(Size {
3203 width: bounds.width,
3204 height: bounds.height,
3205 });
3206 SemanticsDetails::from_configuration(config, on_click_label, is_modal)
3207 }
3208 None => SemanticsDetails::NONE,
3209 };
3210 node.set_details(details);
3211 node.role = role;
3212 node
3213}
3214
3215#[inline(never)]
3216fn build_semantics_node_from_live_nodes(
3217 applier: &mut MemoryApplier,
3218 node: &MeasuredNode,
3219 origin: Option<Point>,
3220) -> Result<SemanticsNode, NodeError> {
3221 let (role, config, (bounds, content), placement) =
3222 match applier.with_node::<LayoutNode, _>(node.node_id, |layout| {
3223 let role = role_from_modifier_slices(&layout.modifier_slices_snapshot());
3224 let config = layout.semantics_configuration();
3225 layout.clear_needs_semantics();
3226 let state = layout.layout_state();
3227 (
3228 role,
3229 config,
3230 semantics_placement(&state, origin),
3231 SemanticsPlacement::of(&state),
3232 )
3233 }) {
3234 Ok(data) => data,
3235 Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => {
3236 match applier.with_node::<SubcomposeLayoutNode, _>(node.node_id, |subcompose| {
3237 subcompose.clear_needs_semantics();
3238 let state = subcompose.layout_state();
3239 (
3240 SemanticsRole::Subcompose,
3241 subcompose.semantics_configuration(),
3242 semantics_placement(&state, origin),
3243 SemanticsPlacement::of(&state),
3244 )
3245 }) {
3246 Ok(data) => data,
3247 Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => {
3248 let top_left = origin.unwrap_or_default();
3249 (
3250 SemanticsRole::Unknown,
3251 None,
3252 (
3253 GeometryRect::from_origin_size(top_left, node.size),
3254 top_left,
3255 ),
3256 SemanticsPlacement::default(),
3257 )
3258 }
3259 Err(err) => return Err(err),
3260 }
3261 }
3262 Err(err) => return Err(err),
3263 };
3264
3265 let mut children = Vec::with_capacity(node.children.len());
3266 for child in &node.children {
3267 children.push(visit_child(applier, child, |applier, child| {
3268 build_semantics_node_from_live_nodes(applier, child, Some(content))
3269 })?);
3270 }
3271
3272 Ok(SemanticsNode {
3273 placement,
3274 ..semantics_node_from_parts(
3275 node.node_id,
3276 applier.node_generation(node.node_id),
3277 role,
3278 config,
3279 children,
3280 None,
3281 bounds,
3282 )
3283 })
3284}
3285
3286fn record_semantics_allocation_stats(node: &SemanticsNode, stats: &mut LayoutAllocationDebugStats) {
3287 stats.semantics_node_count += 1;
3288 stats.semantics_action_count += node.actions.len();
3289 stats.semantics_action_capacity += node.actions.capacity();
3290 stats.semantics_child_count += node.children.len();
3291 stats.semantics_child_capacity += node.children.capacity();
3292 stats.semantics_heap_bytes += node.actions.capacity() * size_of::<SemanticsAction>();
3293 stats.semantics_heap_bytes += node.children.capacity() * size_of::<SemanticsNode>();
3294 if node.details.is_some() {
3295 stats.semantics_heap_bytes += size_of::<SemanticsDetails>();
3296 }
3297
3298 if let Some(description) = &node.description {
3299 stats.semantics_description_count += 1;
3300 stats.semantics_description_bytes += description.capacity();
3301 stats.semantics_heap_bytes += description.capacity();
3302 }
3303
3304 for child in &node.children {
3305 record_semantics_allocation_stats(child, stats);
3306 }
3307}
3308
3309fn record_layout_box_allocation_stats(
3310 layout_box: &LayoutBox,
3311 stats: &mut LayoutAllocationDebugStats,
3312) {
3313 stats.layout_box_count += 1;
3314 stats.layout_box_child_count += layout_box.children.len();
3315 stats.layout_box_child_capacity += layout_box.children.capacity();
3316 stats.layout_box_heap_bytes += layout_box.children.capacity() * size_of::<LayoutBox>();
3317 stats.add_modifier_slice(layout_box.node_data.modifier_slices().debug_stats());
3318
3319 for child in &layout_box.children {
3320 record_layout_box_allocation_stats(child, stats);
3321 }
3322}
3323
3324fn build_layout_tree(
3325 applier: &mut MemoryApplier,
3326 node: &MeasuredNode,
3327) -> Result<LayoutTree, NodeError> {
3328 fn place(
3329 applier: &mut MemoryApplier,
3330 node: &MeasuredNode,
3331 origin: Point,
3332 parent_transform: ProjectiveTransform,
3333 ) -> Result<LayoutBox, NodeError> {
3334 let top_left = Point {
3335 x: origin.x + node.offset.x,
3336 y: origin.y + node.offset.y,
3337 };
3338 let rect = GeometryRect {
3339 x: top_left.x,
3340 y: top_left.y,
3341 width: node.size.width,
3342 height: node.size.height,
3343 };
3344 let (data, window_transform) =
3345 snapshot_node_data(applier, node.node_id, top_left, node.size, parent_transform)?;
3346 let mut children = Vec::with_capacity(node.children.len());
3347 for child in &node.children {
3348 if crate::modifier::is_window_root(applier, child.node_id) {
3349 continue;
3350 }
3351 let child_origin = Point {
3352 x: top_left.x + child.offset.x,
3353 y: top_left.y + child.offset.y,
3354 };
3355 children.push(visit_child(applier, child, |applier, child| {
3356 place(applier, child, child_origin, window_transform)
3357 })?);
3358 }
3359 Ok(LayoutBox {
3360 node_generation: applier.node_generation(node.node_id),
3361 ..LayoutBox::new(node.node_id, rect, node.content_offset, data, children)
3362 })
3363 }
3364
3365 Ok(LayoutTree::new(place(
3366 applier,
3367 node,
3368 Point { x: 0.0, y: 0.0 },
3369 ProjectiveTransform::identity(),
3370 )?))
3371}
3372
3373fn semantics_role_from_layout_box(layout_box: &LayoutBox) -> SemanticsRole {
3374 match &layout_box.node_data.kind {
3375 LayoutNodeKind::Subcompose => SemanticsRole::Subcompose,
3376 LayoutNodeKind::Spacer => SemanticsRole::Spacer,
3377 LayoutNodeKind::Unknown => SemanticsRole::Unknown,
3378 LayoutNodeKind::Button { .. } => SemanticsRole::Button,
3379 LayoutNodeKind::Layout => role_from_modifier_slices(layout_box.node_data.modifier_slices()),
3380 }
3381}
3382
3383#[inline(never)]
3384fn build_semantics_node_from_layout_box(layout_box: &LayoutBox, origin: Point) -> SemanticsNode {
3385 let rect = layout_box.rect;
3386 let content = Point {
3387 x: rect.x + layout_box.content_offset.x,
3388 y: rect.y + layout_box.content_offset.y,
3389 };
3390 let children = layout_box
3391 .children
3392 .iter()
3393 .map(|child| build_semantics_node_from_layout_box(child, content))
3394 .collect();
3395
3396 SemanticsNode {
3397 placement: SemanticsPlacement {
3398 position: Point {
3399 x: rect.x - origin.x,
3400 y: rect.y - origin.y,
3401 },
3402 content_offset: layout_box.content_offset,
3403 },
3404 ..semantics_node_from_parts(
3405 layout_box.node_id,
3406 layout_box.node_generation,
3407 semantics_role_from_layout_box(layout_box),
3408 layout_box.node_data.semantics().cloned(),
3409 children,
3410 None,
3411 rect,
3412 )
3413 }
3414}
3415
3416fn layout_kind_from_metadata(_node_id: NodeId, info: &RuntimeNodeMetadata) -> LayoutNodeKind {
3417 match &info.role {
3418 SemanticsRole::Layout => LayoutNodeKind::Layout,
3419 SemanticsRole::Subcompose => LayoutNodeKind::Subcompose,
3420 SemanticsRole::Text { .. } => LayoutNodeKind::Layout,
3421 SemanticsRole::Spacer => LayoutNodeKind::Spacer,
3422 SemanticsRole::Button => {
3423 let handler = info
3424 .button_handler
3425 .as_ref()
3426 .cloned()
3427 .unwrap_or_else(|| Rc::new(RefCell::new(|| {})));
3428 LayoutNodeKind::Button { on_click: handler }
3429 }
3430 SemanticsRole::Unknown => LayoutNodeKind::Unknown,
3431 }
3432}
3433
3434fn subtract_padding(constraints: Constraints, padding: EdgeInsets) -> Constraints {
3435 let horizontal = padding.horizontal_sum();
3436 let vertical = padding.vertical_sum();
3437 let min_width = (constraints.min_width - horizontal).max(0.0);
3438 let mut max_width = constraints.max_width;
3439 if max_width.is_finite() {
3440 max_width = (max_width - horizontal).max(0.0);
3441 }
3442 let min_height = (constraints.min_height - vertical).max(0.0);
3443 let mut max_height = constraints.max_height;
3444 if max_height.is_finite() {
3445 max_height = (max_height - vertical).max(0.0);
3446 }
3447 normalize_constraints(Constraints {
3448 min_width,
3449 max_width,
3450 min_height,
3451 max_height,
3452 })
3453}
3454
3455fn resolve_dimension(
3456 base: f32,
3457 explicit: DimensionConstraint,
3458 min_override: Option<f32>,
3459 max_override: Option<f32>,
3460 min_limit: f32,
3461 max_limit: f32,
3462) -> f32 {
3463 let mut min_bound = min_limit;
3464 if let Some(min_value) = min_override {
3465 min_bound = min_bound.max(min_value);
3466 }
3467
3468 let mut max_bound = if max_limit.is_finite() {
3469 max_limit
3470 } else {
3471 max_override.unwrap_or(max_limit)
3472 };
3473 if let Some(max_value) = max_override {
3474 if max_bound.is_finite() {
3475 max_bound = max_bound.min(max_value);
3476 } else {
3477 max_bound = max_value;
3478 }
3479 }
3480 if max_bound < min_bound {
3481 max_bound = min_bound;
3482 }
3483
3484 let mut size = match explicit {
3485 DimensionConstraint::Points(points) => points,
3486 DimensionConstraint::Fraction(fraction) => {
3487 if max_limit.is_finite() {
3488 max_limit * fraction.clamp(0.0, 1.0)
3489 } else {
3490 base
3491 }
3492 }
3493 DimensionConstraint::Unspecified => base,
3494 DimensionConstraint::Intrinsic(_) => base,
3495 };
3496
3497 size = clamp_dimension(size, min_bound, max_bound);
3498 size = clamp_dimension(size, min_limit, max_limit);
3499 size.max(0.0)
3500}
3501
3502fn clamp_dimension(value: f32, min: f32, max: f32) -> f32 {
3503 let mut result = value.max(min);
3504 if max.is_finite() {
3505 result = result.min(max);
3506 }
3507 result
3508}
3509
3510fn normalize_constraints(mut constraints: Constraints) -> Constraints {
3511 if constraints.max_width < constraints.min_width {
3512 constraints.max_width = constraints.min_width;
3513 }
3514 if constraints.max_height < constraints.min_height {
3515 constraints.max_height = constraints.min_height;
3516 }
3517 constraints
3518}
3519
3520#[cfg(test)]
3521#[path = "tests/layout_tests.rs"]
3522mod tests;
3523
3524#[cfg(test)]
3525#[path = "tests/semantics_update_tests.rs"]
3526mod semantics_update_tests;
3527
3528#[cfg(test)]
3529#[path = "tests/coordinator_geometry_tests.rs"]
3530mod coordinator_geometry_tests;