1pub mod core;
2pub mod policies;
3mod semantics_labels;
4
5use std::{
6 cell::{Cell, RefCell},
7 fmt,
8 mem::size_of,
9 rc::Rc,
10 sync::OnceLock,
11};
12
13use cranpose_core::{
14 Applier, ApplierHost, Composer, ConcreteApplierHost, MemoryApplier, Node, NodeError, NodeId,
15 Phase, RuntimeHandle, SlotTable, SlotsHost, SnapshotStateObserver,
16};
17use cranpose_foundation::{
18 CanvasSemanticsNode, CollectionInfo, InvalidationKind, LiveRegionMode, ModifierNodeContext,
19 NodeCapabilities, ProgressBarRangeInfo, ScrollAxisRange, SemanticsConfiguration,
20 SemanticsCustomAction, SemanticsDismiss, SemanticsExpand, SemanticsLongClick,
21 SemanticsMagicTap, SemanticsScrollBy, SemanticsScrollToIndex, SemanticsSetProgress,
22 SemanticsSetSelection, SemanticsSetText, SemanticsWidgetRole, text::TextRange,
23};
24use cranpose_ui_layout::{Constraints, MeasurePolicy, PlaceTarget, Placement};
25use web_time::Instant;
26
27#[cfg(test)]
28use self::core::{HorizontalAlignment, VerticalAlignment};
29use self::core::{Measurable, Placeable};
30use crate::{
31 modifier::{
32 DimensionConstraint, EdgeInsets, Modifier, ModifierNodeSlices,
33 ModifierNodeSlicesDebugStats, Point, Rect as GeometryRect, ResolvedModifiers, Size,
34 },
35 subcompose_layout::{CachedBatchMeasureInputs, SubcomposeLayoutNode},
36 widgets::nodes::{IntrinsicKind, LayoutNode, LayoutNodeCacheHandles, LayoutState},
37};
38
39#[derive(Default)]
40pub(crate) struct LayoutNodeContext {
41 invalidations: Vec<InvalidationKind>,
42 update_requested: bool,
43 active_capabilities: Vec<NodeCapabilities>,
44 density: f32,
45}
46
47impl LayoutNodeContext {
48 pub(crate) fn new(density: f32) -> Self {
49 Self {
50 density,
51 ..Self::default()
52 }
53 }
54
55 pub(crate) fn take_invalidations(&mut self) -> Vec<InvalidationKind> {
56 std::mem::take(&mut self.invalidations)
57 }
58}
59
60impl ModifierNodeContext for LayoutNodeContext {
61 fn invalidate(&mut self, kind: InvalidationKind) {
62 if !self.invalidations.contains(&kind) {
63 self.invalidations.push(kind);
64 }
65 }
66
67 fn request_update(&mut self) {
68 self.update_requested = true;
69 }
70
71 fn push_active_capabilities(&mut self, capabilities: NodeCapabilities) {
72 self.active_capabilities.push(capabilities);
73 }
74
75 fn pop_active_capabilities(&mut self) {
76 self.active_capabilities.pop();
77 }
78
79 fn density(&self) -> f32 {
80 self.density
81 }
82}
83
84#[doc(hidden)]
85pub fn invalidate_all_layout_caches() {
86 crate::render_state::invalidate_layout_cache_epoch();
87}
88
89fn layout_measure_telemetry_threshold_ms() -> Option<f64> {
90 static THRESHOLD_MS: OnceLock<Option<f64>> = OnceLock::new();
91 *THRESHOLD_MS.get_or_init(|| {
92 std::env::var("CRANPOSE_LAYOUT_MEASURE_TELEMETRY_MS")
93 .ok()
94 .and_then(|value| value.parse::<f64>().ok())
95 .filter(|value| value.is_finite() && *value >= 0.0)
96 .or_else(|| {
97 std::env::var_os("CRANPOSE_LAYOUT_MEASURE_TELEMETRY")
98 .is_some()
99 .then_some(4.0)
100 })
101 })
102}
103
104struct LayoutMeasureTelemetry {
105 root: NodeId,
106 start: Instant,
107 after_repasses: Instant,
108 after_guard: Instant,
109 after_builder: Instant,
110 after_measure: Instant,
111 after_root_place: Instant,
112 after_aux: Instant,
113 after_builder_drop: Instant,
114 after_guard_drop: Instant,
115}
116
117fn log_layout_measure_telemetry(times: LayoutMeasureTelemetry) {
118 let Some(threshold_ms) = layout_measure_telemetry_threshold_ms() else {
119 return;
120 };
121
122 let total_ms = times
123 .after_guard_drop
124 .duration_since(times.start)
125 .as_secs_f64()
126 * 1000.0;
127 if total_ms < threshold_ms {
128 return;
129 }
130
131 let repass_ms = times
132 .after_repasses
133 .duration_since(times.start)
134 .as_secs_f64()
135 * 1000.0;
136 let guard_ms = times
137 .after_guard
138 .duration_since(times.after_repasses)
139 .as_secs_f64()
140 * 1000.0;
141 let builder_ms = times
142 .after_builder
143 .duration_since(times.after_guard)
144 .as_secs_f64()
145 * 1000.0;
146 let measure_ms = times
147 .after_measure
148 .duration_since(times.after_builder)
149 .as_secs_f64()
150 * 1000.0;
151 let root_place_ms = times
152 .after_root_place
153 .duration_since(times.after_measure)
154 .as_secs_f64()
155 * 1000.0;
156 let aux_ms = times
157 .after_aux
158 .duration_since(times.after_root_place)
159 .as_secs_f64()
160 * 1000.0;
161 let builder_drop_ms = times
162 .after_builder_drop
163 .duration_since(times.after_aux)
164 .as_secs_f64()
165 * 1000.0;
166 let guard_drop_ms = times
167 .after_guard_drop
168 .duration_since(times.after_builder_drop)
169 .as_secs_f64()
170 * 1000.0;
171 log::warn!(
172 "[layout-measure-telemetry] root={} total_ms={total_ms:.2} repass_ms={repass_ms:.2} guard_ms={guard_ms:.2} builder_ms={builder_ms:.2} measure_ms={measure_ms:.2} root_place_ms={root_place_ms:.2} aux_ms={aux_ms:.2} builder_drop_ms={builder_drop_ms:.2} guard_drop_ms={guard_drop_ms:.2}",
173 times.root
174 );
175}
176
177fn log_node_measure_telemetry(
178 kind: &'static str,
179 node_id: NodeId,
180 constraints: Constraints,
181 size: Size,
182 children: usize,
183 start: Instant,
184) {
185 let Some(threshold_ms) = layout_measure_telemetry_threshold_ms() else {
186 return;
187 };
188
189 let total_ms = start.elapsed().as_secs_f64() * 1000.0;
190 if total_ms < threshold_ms {
191 return;
192 }
193
194 log::warn!(
195 "[layout-node-telemetry] kind={kind} node={} total_ms={total_ms:.2} constraints=({:.1},{:.1},{:.1},{:.1}) size=({:.1},{:.1}) children={children}",
196 node_id,
197 constraints.min_width,
198 constraints.max_width,
199 constraints.min_height,
200 constraints.max_height,
201 size.width,
202 size.height,
203 );
204}
205
206struct ApplierSlotGuard<'a> {
207 target: &'a mut MemoryApplier,
208 host: Rc<ConcreteApplierHost<MemoryApplier>>,
209 slots: Rc<RefCell<SlotTable>>,
210}
211
212impl<'a> ApplierSlotGuard<'a> {
213 fn new(target: &'a mut MemoryApplier) -> Self {
214 let original_applier = std::mem::replace(target, MemoryApplier::new());
215 let host = Rc::new(ConcreteApplierHost::new(original_applier));
216
217 let slots = {
218 let mut applier_ref = host.borrow_typed();
219 std::mem::take(applier_ref.slots())
220 };
221 let slots = Rc::new(RefCell::new(slots));
222
223 Self {
224 target,
225 host,
226 slots,
227 }
228 }
229
230 fn host(&self) -> Rc<ConcreteApplierHost<MemoryApplier>> {
231 Rc::clone(&self.host)
232 }
233
234 fn slots_handle(&self) -> Rc<RefCell<SlotTable>> {
235 Rc::clone(&self.slots)
236 }
237}
238
239impl Drop for ApplierSlotGuard<'_> {
240 fn drop(&mut self) {
241 {
242 let mut applier_ref = self.host.borrow_typed();
243 *applier_ref.slots() = std::mem::take(&mut *self.slots.borrow_mut());
244 }
245
246 {
247 let mut applier_ref = self.host.borrow_typed();
248 let original_applier = std::mem::take(&mut *applier_ref);
249 let _ = std::mem::replace(self.target, original_applier);
250 }
251 }
252}
253
254struct ModifierChainMeasurement {
255 size: Size,
256 content_offset: Point,
257 offset: Point,
258 window_root: bool,
259}
260
261type LayoutModifierNodeData = (
262 usize,
263 Rc<RefCell<Box<dyn cranpose_foundation::ModifierNode>>>,
264);
265
266struct ScratchVecPool<T> {
267 available: Vec<Vec<T>>,
268}
269
270impl<T> ScratchVecPool<T> {
271 fn acquire(&mut self) -> Vec<T> {
272 self.available.pop().unwrap_or_default()
273 }
274
275 fn release(&mut self, mut values: Vec<T>) {
276 values.clear();
277 self.available.push(values);
278 }
279
280 #[cfg(test)]
281 fn available_count(&self) -> usize {
282 self.available.len()
283 }
284}
285
286impl<T> Default for ScratchVecPool<T> {
287 fn default() -> Self {
288 Self {
289 available: Vec::new(),
290 }
291 }
292}
293
294#[derive(Default)]
295pub(crate) struct FrameLayoutArena {
296 tmp_records: ScratchVecPool<(NodeId, ChildRecord)>,
297 tmp_child_ids: ScratchVecPool<NodeId>,
298 tmp_layout_node_data: ScratchVecPool<LayoutModifierNodeData>,
299 tmp_placements: ScratchVecPool<Placement>,
300}
301
302#[cfg(test)]
303impl FrameLayoutArena {
304 pub(crate) fn available_placement_scratch_count(&self) -> usize {
305 self.tmp_placements.available_count()
306 }
307
308 pub(crate) fn seed_placement_scratch_for_test(&mut self) {
309 self.tmp_placements.release(Vec::with_capacity(1));
310 }
311}
312
313#[derive(Clone, Debug, PartialEq, Eq)]
315pub struct SemanticsCallback {
316 node_id: NodeId,
317}
318
319impl SemanticsCallback {
320 pub fn new(node_id: NodeId) -> Self {
321 Self { node_id }
322 }
323
324 pub fn node_id(&self) -> NodeId {
325 self.node_id
326 }
327}
328
329#[derive(Clone, Debug, PartialEq, Eq)]
331pub enum SemanticsAction {
332 Click { handler: SemanticsCallback },
333}
334
335#[derive(Clone, Debug)]
338pub struct SemanticsText(Rc<crate::text::AnnotatedString>);
339
340impl SemanticsText {
341 pub fn as_str(&self) -> &str {
343 &self.0.text
344 }
345}
346
347impl PartialEq for SemanticsText {
348 fn eq(&self, other: &Self) -> bool {
349 self.as_str() == other.as_str()
350 }
351}
352
353impl Eq for SemanticsText {}
354
355impl From<&str> for SemanticsText {
356 fn from(text: &str) -> Self {
357 Self(Rc::new(crate::text::AnnotatedString::from(text)))
358 }
359}
360
361#[derive(Clone, Debug, PartialEq, Eq)]
364pub enum SemanticsRole {
365 Layout,
367 Subcompose,
369 Text { value: SemanticsText },
371 Spacer,
373 Button,
375 Unknown,
377}
378
379#[derive(Clone, Debug, PartialEq)]
386pub struct SemanticsNode {
387 pub node_id: NodeId,
388 pub bounds: GeometryRect,
391 pub node_generation: u32,
393 pub role: SemanticsRole,
395 pub widget_role: Option<SemanticsWidgetRole>,
399 pub actions: Vec<SemanticsAction>,
400 pub children: Vec<SemanticsNode>,
401 pub description: Option<String>,
402 pub state_description: Option<String>,
403 pub on_click_label: Option<String>,
404 pub on_click: Option<SemanticsCustomAction>,
406 pub on_long_click: Option<SemanticsLongClick>,
408 pub on_long_click_label: Option<String>,
410 pub on_magic_tap: Option<SemanticsMagicTap>,
412 pub on_magic_tap_label: Option<String>,
414 pub input_labels: Vec<String>,
416 pub language: Option<String>,
418 pub selected: Option<bool>,
419 pub toggled: Option<bool>,
420 pub enabled: bool,
421 pub custom_actions: Vec<SemanticsCustomAction>,
422 pub canvas_children: Vec<CanvasSemanticsNode>,
425 pub editable_text: bool,
426 pub multiline: bool,
428 pub hidden: bool,
430 pub is_modal: bool,
432 pub merge_descendants: bool,
435 pub selectable_group: bool,
437 pub pane_title: Option<String>,
439 pub error: Option<String>,
441 pub password: bool,
443 pub traversal_index: f32,
445 pub text: Option<String>,
447 pub text_selection: Option<TextRange>,
448 pub focusable: bool,
451 pub focused: bool,
453 pub live_region: Option<LiveRegionMode>,
456 pub progress: Option<ProgressBarRangeInfo>,
459 pub set_progress: Option<SemanticsSetProgress>,
461 pub set_text: Option<SemanticsSetText>,
463 pub set_selection: Option<SemanticsSetSelection>,
466 pub expand: Option<SemanticsExpand>,
468 pub collapse: Option<SemanticsExpand>,
470 pub dismiss: Option<SemanticsDismiss>,
472 pub vertical_scroll: Option<ScrollAxisRange>,
474 pub horizontal_scroll: Option<ScrollAxisRange>,
476 pub scroll_by: Option<SemanticsScrollBy>,
478 pub scroll_to_index: Option<SemanticsScrollToIndex>,
480 pub collection: Option<CollectionInfo>,
482}
483
484impl Default for SemanticsNode {
485 fn default() -> Self {
486 Self {
487 node_id: 0,
488 bounds: GeometryRect::EMPTY,
489 node_generation: 0,
490 role: SemanticsRole::Unknown,
491 widget_role: None,
492 actions: Vec::new(),
493 children: Vec::new(),
494 description: None,
495 state_description: None,
496 on_click_label: None,
497 on_click: None,
498 on_long_click: None,
499 on_long_click_label: None,
500 on_magic_tap: None,
501 on_magic_tap_label: None,
502 input_labels: Vec::new(),
503 language: None,
504 selected: None,
505 toggled: None,
506 enabled: true,
507 custom_actions: Vec::new(),
508 canvas_children: Vec::new(),
509 editable_text: false,
510 multiline: false,
511 hidden: false,
512 is_modal: false,
513 merge_descendants: false,
514 selectable_group: false,
515 pane_title: None,
516 error: None,
517 password: false,
518 traversal_index: 0.0,
519 text: None,
520 text_selection: None,
521 focusable: false,
522 focused: false,
523 live_region: None,
524 progress: None,
525 set_progress: None,
526 set_text: None,
527 set_selection: None,
528 expand: None,
529 collapse: None,
530 dismiss: None,
531 vertical_scroll: None,
532 horizontal_scroll: None,
533 scroll_by: None,
534 scroll_to_index: None,
535 collection: None,
536 }
537 }
538}
539
540#[derive(Clone, Debug, PartialEq)]
542pub struct SemanticsTree {
543 full: SemanticsNode,
546 modal: Option<Vec<usize>>,
549}
550
551impl SemanticsTree {
552 fn new(full: SemanticsNode) -> Self {
553 let modal = top_modal_path(&full);
554 Self { full, modal }
555 }
556
557 pub fn root(&self) -> &SemanticsNode {
559 self.modal.as_deref().map_or(&self.full, |path| {
560 path.iter()
561 .try_fold(&self.full, |node, &index| node.children.get(index))
562 .unwrap_or(&self.full)
563 })
564 }
565}
566
567fn modal_takes_space(size: Size) -> bool {
569 size.width > 0.0 && size.height > 0.0 && size.width.is_finite() && size.height.is_finite()
570}
571
572fn top_modal_path(root: &SemanticsNode) -> Option<Vec<usize>> {
575 fn search(node: &SemanticsNode, path: &mut Vec<usize>) -> bool {
576 if node.hidden {
577 return false;
578 }
579 for (index, child) in node.children.iter().enumerate().rev() {
580 path.push(index);
581 if search(child, path) {
582 return true;
583 }
584 path.pop();
585 }
586 node.is_modal
587 }
588 let mut path = Vec::new();
589 search(root, &mut path).then_some(path)
590}
591
592#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
593pub struct LayoutAllocationDebugStats {
594 pub layout_box_count: usize,
595 pub layout_box_child_count: usize,
596 pub layout_box_child_capacity: usize,
597 pub layout_box_heap_bytes: usize,
598 pub modifier_slice_count: usize,
599 pub modifier_slice_heap_bytes: usize,
600 pub modifier_draw_command_count: usize,
601 pub modifier_draw_command_capacity: usize,
602 pub modifier_pointer_input_count: usize,
603 pub modifier_pointer_input_capacity: usize,
604 pub modifier_text_content_count: usize,
605 pub modifier_text_style_count: usize,
606 pub modifier_text_layout_options_count: usize,
607 pub modifier_prepared_text_layout_count: usize,
608 pub modifier_graphics_layer_count: usize,
609 pub modifier_graphics_layer_resolver_count: usize,
610 pub semantics_node_count: usize,
611 pub semantics_action_count: usize,
612 pub semantics_action_capacity: usize,
613 pub semantics_child_count: usize,
614 pub semantics_child_capacity: usize,
615 pub semantics_description_count: usize,
616 pub semantics_description_bytes: usize,
617 pub semantics_heap_bytes: usize,
618}
619
620impl LayoutAllocationDebugStats {
621 fn add_modifier_slice(&mut self, stats: ModifierNodeSlicesDebugStats) {
622 self.modifier_slice_count += 1;
623 self.modifier_slice_heap_bytes += stats.heap_bytes;
624 self.modifier_draw_command_count += stats.draw_command_count;
625 self.modifier_draw_command_capacity += stats.draw_command_capacity;
626 self.modifier_pointer_input_count += stats.pointer_input_count;
627 self.modifier_pointer_input_capacity += stats.pointer_input_capacity;
628 self.modifier_text_content_count += usize::from(stats.has_text_content);
629 self.modifier_text_style_count += usize::from(stats.has_text_style);
630 self.modifier_text_layout_options_count += usize::from(stats.has_text_layout_options);
631 self.modifier_prepared_text_layout_count += usize::from(stats.has_prepared_text_layout);
632 self.modifier_graphics_layer_count += usize::from(stats.has_graphics_layer);
633 self.modifier_graphics_layer_resolver_count +=
634 usize::from(stats.has_graphics_layer_resolver);
635 }
636}
637
638#[derive(Debug, Clone)]
640pub struct LayoutTree {
641 root: LayoutBox,
642}
643
644impl LayoutTree {
645 pub fn new(root: LayoutBox) -> Self {
646 Self { root }
647 }
648
649 pub fn root(&self) -> &LayoutBox {
650 &self.root
651 }
652
653 pub fn root_mut(&mut self) -> &mut LayoutBox {
654 &mut self.root
655 }
656
657 pub fn into_root(self) -> LayoutBox {
658 self.root
659 }
660
661 pub fn debug_allocation_stats(&self) -> LayoutAllocationDebugStats {
662 let mut stats = LayoutAllocationDebugStats::default();
663 record_layout_box_allocation_stats(&self.root, &mut stats);
664 stats
665 }
666}
667
668#[derive(Debug, Clone)]
670pub struct LayoutBox {
671 pub node_id: NodeId,
672 pub node_generation: u32,
674 pub rect: GeometryRect,
675 pub content_offset: Point,
677 pub node_data: LayoutNodeData,
678 pub children: Vec<LayoutBox>,
679}
680
681impl LayoutBox {
682 pub fn new(
683 node_id: NodeId,
684 rect: GeometryRect,
685 content_offset: Point,
686 node_data: LayoutNodeData,
687 children: Vec<LayoutBox>,
688 ) -> Self {
689 Self {
690 node_id,
691 node_generation: 0,
692 rect,
693 content_offset,
694 node_data,
695 children,
696 }
697 }
698}
699
700#[derive(Debug, Clone)]
702pub struct LayoutNodeData {
703 #[cfg(feature = "inspection")]
705 pub source_trace: Rc<[cranpose_core::source_trace::SourceLocation]>,
706 pub modifier: Modifier,
707 pub resolved_modifiers: ResolvedModifiers,
708 pub modifier_slices: Rc<ModifierNodeSlices>,
709 pub semantics: Option<Rc<SemanticsConfiguration>>,
710 pub kind: LayoutNodeKind,
711}
712
713impl LayoutNodeData {
714 pub fn new(
715 modifier: Modifier,
716 resolved_modifiers: ResolvedModifiers,
717 modifier_slices: Rc<ModifierNodeSlices>,
718 semantics: Option<Rc<SemanticsConfiguration>>,
719 kind: LayoutNodeKind,
720 ) -> Self {
721 Self {
722 #[cfg(feature = "inspection")]
723 source_trace: Rc::default(),
724 modifier,
725 resolved_modifiers,
726 modifier_slices,
727 semantics,
728 kind,
729 }
730 }
731
732 pub fn semantics(&self) -> Option<&SemanticsConfiguration> {
735 self.semantics.as_deref()
736 }
737
738 pub fn resolved_modifiers(&self) -> ResolvedModifiers {
739 self.resolved_modifiers
740 }
741
742 pub fn modifier_slices(&self) -> &ModifierNodeSlices {
743 &self.modifier_slices
744 }
745}
746
747#[derive(Clone)]
754pub enum LayoutNodeKind {
755 Layout,
756 Subcompose,
757 Spacer,
758 Button { on_click: Rc<RefCell<dyn FnMut()>> },
759 Unknown,
760}
761
762impl fmt::Debug for LayoutNodeKind {
763 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
764 match self {
765 LayoutNodeKind::Layout => f.write_str("Layout"),
766 LayoutNodeKind::Subcompose => f.write_str("Subcompose"),
767 LayoutNodeKind::Spacer => f.write_str("Spacer"),
768 LayoutNodeKind::Button { .. } => f.write_str("Button"),
769 LayoutNodeKind::Unknown => f.write_str("Unknown"),
770 }
771 }
772}
773
774pub trait LayoutEngine {
776 fn compute_layout(&mut self, root: NodeId, max_size: Size) -> Result<LayoutTree, NodeError>;
777}
778
779impl LayoutEngine for MemoryApplier {
780 fn compute_layout(&mut self, root: NodeId, max_size: Size) -> Result<LayoutTree, NodeError> {
781 let measurements = measure_layout(self, root, max_size)?;
782 measurements
783 .into_layout_tree()
784 .ok_or(NodeError::MissingContext {
785 id: root,
786 reason: "layout tree was not requested",
787 })
788 }
789}
790
791#[derive(Debug, Clone)]
793pub struct LayoutMeasurements {
794 root: Rc<MeasuredNode>,
795 semantics: Option<SemanticsTree>,
796 layout_tree: Option<LayoutTree>,
797}
798
799impl LayoutMeasurements {
800 fn new(
801 root: Rc<MeasuredNode>,
802 semantics: Option<SemanticsTree>,
803 layout_tree: Option<LayoutTree>,
804 ) -> Self {
805 Self {
806 root,
807 semantics,
808 layout_tree,
809 }
810 }
811
812 pub fn root_size(&self) -> Size {
814 self.root.size
815 }
816
817 pub fn semantics_tree(&self) -> Option<&SemanticsTree> {
818 self.semantics.as_ref()
819 }
820
821 pub fn debug_allocation_stats(&self) -> LayoutAllocationDebugStats {
822 let mut stats = self
823 .layout_tree
824 .as_ref()
825 .map(LayoutTree::debug_allocation_stats)
826 .unwrap_or_default();
827 if let Some(semantics) = &self.semantics {
828 record_semantics_allocation_stats(semantics.root(), &mut stats);
829 }
830 stats
831 }
832
833 pub fn into_layout_tree(self) -> Option<LayoutTree> {
835 self.layout_tree
836 }
837
838 pub fn layout_tree(&self) -> Option<LayoutTree> {
840 self.layout_tree.clone()
841 }
842}
843
844pub fn build_semantics_tree_from_layout_tree(layout_tree: &LayoutTree) -> SemanticsTree {
849 SemanticsTree::new(build_semantics_node_from_layout_box(layout_tree.root()))
850}
851
852pub fn build_layout_tree_from_applier(
858 applier: &mut MemoryApplier,
859 root: NodeId,
860) -> Result<Option<LayoutTree>, NodeError> {
861 let origin = layout_tree_origin(read_layout_node(applier, root, |state, _| state)?);
862 let mut child_stack = Vec::new();
863 place_layout_box(applier, root, origin, Point::default(), &mut child_stack)
864 .map(|root| root.map(LayoutTree::new))
865}
866
867fn layout_tree_origin(root: Option<LayoutState>) -> Point {
868 let Some(state) = root else {
869 return Point::default();
870 };
871 let position = state.position();
872 Point {
873 x: -position.x,
874 y: -position.y,
875 }
876}
877
878fn read_layout_node<R>(
881 applier: &mut MemoryApplier,
882 node_id: NodeId,
883 mut read: impl FnMut(LayoutState, &[NodeId]) -> R,
884) -> Result<Option<R>, NodeError> {
885 match applier
886 .with_node::<LayoutNode, _>(node_id, |node| read(node.layout_state(), &node.children))
887 {
888 Ok(value) => return Ok(Some(value)),
889 Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => {}
890 Err(err) => return Err(err),
891 }
892
893 match applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
894 let state = node.layout_state();
895 node.with_active_children(|children| read(state, children))
896 }) {
897 Ok(value) => Ok(Some(value)),
898 Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => Ok(None),
899 Err(err) => Err(err),
900 }
901}
902
903fn snapshot_node_data(
904 applier: &mut MemoryApplier,
905 node_id: NodeId,
906 top_left: Point,
907 size: Size,
908 parent_layer_translation: Point,
909) -> Result<(LayoutNodeData, Point), NodeError> {
910 let info = runtime_metadata_for(applier, node_id)?;
911 let kind = layout_kind_from_metadata(node_id, &info);
912 let RuntimeNodeMetadata {
913 modifier,
914 resolved_modifiers,
915 modifier_slices,
916 semantics,
917 ..
918 } = info;
919
920 let layer_translation = match modifier_slices.graphics_layer() {
921 Some(layer) => Point {
922 x: parent_layer_translation.x + layer.translation_x,
923 y: parent_layer_translation.y + layer.translation_y,
924 },
925 None => parent_layer_translation,
926 };
927
928 publish_window_geometry(&modifier_slices, top_left, layer_translation, size);
929
930 let data = LayoutNodeData::new(
931 modifier,
932 resolved_modifiers,
933 modifier_slices,
934 semantics,
935 kind,
936 );
937 #[cfg(feature = "inspection")]
938 let data = {
939 let mut data = data;
940 data.source_trace = applier
941 .with_node::<LayoutNode, _>(node_id, |node| node.source_trace.clone())
942 .unwrap_or_default();
943 data
944 };
945 Ok((data, layer_translation))
946}
947
948fn place_layout_box(
953 applier: &mut MemoryApplier,
954 node_id: NodeId,
955 parent_content_origin: Point,
956 parent_layer_translation: Point,
957 child_stack: &mut Vec<NodeId>,
958) -> Result<Option<LayoutBox>, NodeError> {
959 let first_child = child_stack.len();
960 let Some(state) = read_layout_node(applier, node_id, |state, children| {
961 if state.is_placed() {
962 child_stack.extend_from_slice(children);
963 }
964 state
965 })?
966 else {
967 return Ok(None);
968 };
969 if !state.is_placed() {
970 return Ok(None);
971 }
972
973 let top_left = Point {
974 x: parent_content_origin.x + state.position().x,
975 y: parent_content_origin.y + state.position().y,
976 };
977 let rect = GeometryRect {
978 x: top_left.x,
979 y: top_left.y,
980 width: state.size().width,
981 height: state.size().height,
982 };
983 let (data, layer_translation) = snapshot_node_data(
984 applier,
985 node_id,
986 top_left,
987 state.size(),
988 parent_layer_translation,
989 )?;
990 let child_origin = Point {
991 x: top_left.x + state.content_offset.x,
992 y: top_left.y + state.content_offset.y,
993 };
994 let end = child_stack.len();
995 let mut children = Vec::with_capacity(end - first_child);
996 for index in first_child..end {
997 let child_id = child_stack[index];
998 if crate::modifier::is_window_root(applier, child_id) {
999 continue;
1000 }
1001 if let Some(child) = place_layout_box(
1002 applier,
1003 child_id,
1004 child_origin,
1005 layer_translation,
1006 child_stack,
1007 )? {
1008 children.push(child);
1009 }
1010 }
1011 child_stack.truncate(first_child);
1012
1013 Ok(Some(LayoutBox {
1014 node_generation: applier.node_generation(node_id),
1015 ..LayoutBox::new(node_id, rect, state.content_offset, data, children)
1016 }))
1017}
1018
1019fn semantics_placement(
1024 state: &crate::widgets::nodes::layout_node::LayoutState,
1025 origin: Option<Point>,
1026) -> (GeometryRect, Point) {
1027 let top_left = origin.map_or_else(Point::default, |origin| Point {
1028 x: origin.x + state.position().x,
1029 y: origin.y + state.position().y,
1030 });
1031 let content = Point {
1032 x: top_left.x + state.content_offset.x,
1033 y: top_left.y + state.content_offset.y,
1034 };
1035 (
1036 GeometryRect::from_origin_size(top_left, state.size()),
1037 content,
1038 )
1039}
1040
1041pub fn build_semantics_tree_from_applier(
1047 applier: &mut MemoryApplier,
1048 root: NodeId,
1049) -> Result<Option<SemanticsTree>, NodeError> {
1050 let mut tree = None;
1051 update_semantics_tree_from_applier(applier, root, &mut tree)?;
1052 Ok(tree)
1053}
1054
1055pub fn update_semantics_tree_from_applier(
1062 applier: &mut MemoryApplier,
1063 root: NodeId,
1064 tree: &mut Option<SemanticsTree>,
1065) -> Result<(), NodeError> {
1066 let (mut node, known) = match tree.take() {
1067 Some(tree) => {
1068 let known = tree.full.node_id == root;
1069 (tree.full, known)
1070 }
1071 None => (SemanticsNode::default(), false),
1072 };
1073 let mut update = SemanticsUpdate {
1074 applier,
1075 child_stack: Vec::new(),
1076 saw_modal: false,
1077 };
1078 if update.node(root, None, &mut node, known)? {
1079 let modal = if update.saw_modal {
1080 top_modal_path(&node)
1081 } else {
1082 None
1083 };
1084 *tree = Some(SemanticsTree { full: node, modal });
1085 }
1086 Ok(())
1087}
1088
1089struct SemanticsUpdate<'a> {
1091 applier: &'a mut MemoryApplier,
1092 child_stack: Vec<NodeId>,
1095 saw_modal: bool,
1097}
1098
1099type SemanticsVisit = (
1102 Option<(SemanticsRole, Option<SemanticsConfiguration>)>,
1103 bool,
1104 (GeometryRect, Point),
1105);
1106
1107impl SemanticsUpdate<'_> {
1108 fn node(
1112 &mut self,
1113 node_id: NodeId,
1114 origin: Option<Point>,
1115 node: &mut SemanticsNode,
1116 known: bool,
1117 ) -> Result<bool, NodeError> {
1118 let generation = self.applier.node_generation(node_id);
1119 let same = known && node.node_generation == generation;
1120 let first_child = self.child_stack.len();
1121 let Some((content, requests_modal, (bounds, content_origin))) =
1122 self.visit(node_id, origin, same)?
1123 else {
1124 return Ok(false);
1125 };
1126 match content {
1127 Some((role, config)) => {
1128 let mut children = std::mem::take(&mut node.children);
1129 if !same {
1130 children.clear();
1131 }
1132 *node =
1133 semantics_node_from_parts(node_id, generation, role, config, children, bounds);
1134 }
1135 None => {
1136 node.is_modal = requests_modal
1137 && modal_takes_space(Size {
1138 width: bounds.width,
1139 height: bounds.height,
1140 });
1141 node.bounds = bounds;
1142 }
1143 }
1144 self.saw_modal |= node.is_modal;
1145 self.children(&mut node.children, first_child, content_origin)?;
1146 Ok(true)
1147 }
1148
1149 fn visit(
1153 &mut self,
1154 node_id: NodeId,
1155 origin: Option<Point>,
1156 same: bool,
1157 ) -> Result<Option<SemanticsVisit>, NodeError> {
1158 let child_stack = &mut self.child_stack;
1159 match self.applier.with_node::<LayoutNode, _>(node_id, |layout| {
1160 let state = layout.layout_state();
1161 if !state.is_placed() {
1162 return None;
1163 }
1164 let reach = (same && !layout.semantics_changed()).then(|| layout.semantics_reach());
1167 let content = match reach {
1168 Some(reach) if !reach.merges_live_state => None,
1169 _ => Some((
1170 role_from_modifier_slices(&layout.modifier_slices_snapshot()),
1171 layout.semantics_configuration(),
1172 )),
1173 };
1174 child_stack.extend_from_slice(&layout.children);
1175 layout.clear_needs_semantics();
1176 let requests_modal = reach.is_some_and(|reach| reach.is_modal);
1177 Some((content, requests_modal, semantics_placement(&state, origin)))
1178 }) {
1179 Ok(visit) => return Ok(visit),
1180 Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => {}
1181 Err(err) => return Err(err),
1182 }
1183 match self
1186 .applier
1187 .with_node::<SubcomposeLayoutNode, _>(node_id, |subcompose| {
1188 let state = subcompose.layout_state();
1189 if !state.is_placed() {
1190 return None;
1191 }
1192 let config = subcompose.semantics_configuration();
1193 subcompose.with_active_children(|children| child_stack.extend_from_slice(children));
1194 subcompose.clear_needs_semantics();
1195 Some((
1196 Some((SemanticsRole::Subcompose, config)),
1197 false,
1198 semantics_placement(&state, origin),
1199 ))
1200 }) {
1201 Ok(visit) => Ok(visit),
1202 Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => Ok(None),
1203 Err(err) => Err(err),
1204 }
1205 }
1206
1207 fn children(
1214 &mut self,
1215 children: &mut Vec<SemanticsNode>,
1216 first_child: usize,
1217 content: Point,
1218 ) -> Result<(), NodeError> {
1219 let end = self.child_stack.len();
1220 let mut held = HeldChildren::default();
1221 let mut in_place = true;
1222 let mut kept = 0;
1223 for index in first_child..end {
1224 let child_id = self.child_stack[index];
1225 if crate::modifier::is_window_root(self.applier, child_id) {
1226 continue;
1227 }
1228 if in_place {
1229 if let Some(offset) = children[kept..]
1230 .iter()
1231 .position(|child| child.node_id == child_id)
1232 {
1233 held.extend(children.drain(kept..kept + offset));
1234 if self.node(child_id, Some(content), &mut children[kept], true)? {
1235 kept += 1;
1236 } else {
1237 children.remove(kept);
1238 }
1239 continue;
1240 }
1241 held.extend(children.drain(kept..));
1242 in_place = false;
1243 }
1244 let taken = held.take(child_id);
1245 let known = taken.is_some();
1246 let mut child = taken.unwrap_or_default();
1247 if self.node(child_id, Some(content), &mut child, known)? {
1248 children.push(child);
1249 }
1250 }
1251 if in_place {
1252 children.truncate(kept);
1253 }
1254 self.child_stack.truncate(first_child);
1255 Ok(())
1256 }
1257}
1258
1259#[derive(Default)]
1262struct HeldChildren {
1263 nodes: Vec<SemanticsNode>,
1264 positions: cranpose_core::collections::map::HashMap<NodeId, usize>,
1265}
1266
1267impl HeldChildren {
1268 fn extend(&mut self, nodes: impl Iterator<Item = SemanticsNode>) {
1269 for node in nodes {
1270 self.positions.insert(node.node_id, self.nodes.len());
1271 self.nodes.push(node);
1272 }
1273 }
1274
1275 fn take(&mut self, node_id: NodeId) -> Option<SemanticsNode> {
1277 let position = self.positions.remove(&node_id)?;
1278 let node = self.nodes.swap_remove(position);
1279 if let Some(moved) = self.nodes.get(position) {
1280 self.positions.insert(moved.node_id, position);
1281 }
1282 Some(node)
1283 }
1284}
1285
1286fn write_node_geometry(
1290 geometry: Option<&crate::modifier::CoordinatorGeometry>,
1291 node_id: NodeId,
1292 write: impl FnOnce(&crate::modifier::CoordinatorGeometry) -> bool,
1293) {
1294 if geometry.is_some_and(write) {
1295 crate::render_state::record_geometry_scene_node(node_id);
1296 }
1297}
1298
1299pub fn top_modal_from_applier(
1304 applier: &mut MemoryApplier,
1305 root: NodeId,
1306) -> Result<Option<NodeId>, NodeError> {
1307 enum Step {
1312 Enter { node: NodeId, child: bool },
1313 Modal(NodeId),
1314 }
1315
1316 fn push_placed(
1317 steps: &mut Vec<Step>,
1318 node: NodeId,
1319 reach: cranpose_foundation::SemanticsReach,
1320 size: Size,
1321 children: impl IntoIterator<Item = NodeId>,
1322 ) {
1323 if reach.hidden {
1324 return;
1325 }
1326 if reach.is_modal && modal_takes_space(size) {
1327 steps.push(Step::Modal(node));
1328 }
1329 steps.extend(
1330 children
1331 .into_iter()
1332 .map(|node| Step::Enter { node, child: true }),
1333 );
1334 }
1335
1336 let mut steps = vec![Step::Enter {
1337 node: root,
1338 child: false,
1339 }];
1340 while let Some(step) = steps.pop() {
1341 let (node_id, child) = match step {
1342 Step::Modal(node) => return Ok(Some(node)),
1343 Step::Enter { node, child } => (node, child),
1344 };
1345 let node = match applier.get_mut(node_id) {
1346 Ok(node) => node.as_any_mut(),
1347 Err(NodeError::Missing { .. }) => continue,
1348 Err(error) => return Err(error),
1349 };
1350 if let Some(layout) = node.downcast_mut::<LayoutNode>() {
1351 let state = layout.layout_state();
1352 if state.is_placed() && !(child && layout.is_window_root()) {
1353 let children = layout.children.iter().copied();
1354 push_placed(
1355 &mut steps,
1356 node_id,
1357 layout.semantics_reach(),
1358 state.size(),
1359 children,
1360 );
1361 }
1362 } else if let Some(subcompose) = node.downcast_mut::<SubcomposeLayoutNode>() {
1363 let state = subcompose.layout_state();
1364 if state.is_placed() {
1365 let reach = subcompose.semantics_reach();
1366 subcompose.with_active_children(|children| {
1367 push_placed(
1368 &mut steps,
1369 node_id,
1370 reach,
1371 state.size(),
1372 children.iter().copied(),
1373 );
1374 });
1375 }
1376 }
1377 }
1378 Ok(None)
1379}
1380
1381#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1382pub struct MeasureLayoutOptions {
1383 pub collect_semantics: bool,
1384 pub build_layout_tree: bool,
1385}
1386
1387impl Default for MeasureLayoutOptions {
1388 fn default() -> Self {
1389 Self {
1390 collect_semantics: true,
1391 build_layout_tree: true,
1392 }
1393 }
1394}
1395
1396pub fn tree_needs_layout(applier: &mut dyn Applier, root: NodeId) -> Result<bool, NodeError> {
1404 Ok(applier.get_mut(root)?.needs_layout())
1405}
1406
1407fn publish_window_geometry(
1408 modifier_slices: &crate::modifier::ModifierNodeSlices,
1409 top_left: Point,
1410 layer_translation: Point,
1411 size: Size,
1412) {
1413 let origin = Point {
1414 x: top_left.x + layer_translation.x,
1415 y: top_left.y + layer_translation.y,
1416 };
1417 if let Some(sink) = modifier_slices.text_window_origin() {
1418 sink.set(origin);
1419 }
1420 if let Some(sink) = modifier_slices.viewport_window_rect() {
1421 sink.set(GeometryRect {
1422 x: origin.x,
1423 y: origin.y,
1424 width: size.width,
1425 height: size.height,
1426 });
1427 }
1428 modifier_slices.publish_pointer_input_size(size);
1429}
1430
1431pub fn tree_needs_semantics(applier: &mut dyn Applier, root: NodeId) -> Result<bool, NodeError> {
1437 Ok(applier.get_mut(root)?.needs_semantics())
1438}
1439
1440#[cfg(test)]
1441pub(crate) fn bubble_layout_dirty(applier: &mut MemoryApplier, node_id: NodeId) {
1442 cranpose_core::bubble_layout_dirty(applier as &mut dyn Applier, node_id);
1443}
1444
1445pub fn measure_layout(
1447 applier: &mut MemoryApplier,
1448 root: NodeId,
1449 max_size: Size,
1450) -> Result<LayoutMeasurements, NodeError> {
1451 measure_layout_with_options(applier, root, max_size, MeasureLayoutOptions::default())
1452}
1453
1454pub fn measure_layout_with_options(
1455 applier: &mut MemoryApplier,
1456 root: NodeId,
1457 max_size: Size,
1458 options: MeasureLayoutOptions,
1459) -> Result<LayoutMeasurements, NodeError> {
1460 let telemetry_start = Instant::now();
1461 crate::render_state::begin_text_layout_pass();
1462 process_pending_layout_repasses(applier, root)?;
1463 let after_repasses = Instant::now();
1464
1465 let constraints = Constraints {
1466 min_width: 0.0,
1467 max_width: max_size.width,
1468 min_height: 0.0,
1469 max_height: max_size.height,
1470 };
1471
1472 let (needs_remeasure, _needs_semantics, cached_epoch) = match applier
1473 .with_node::<LayoutNode, _>(root, |node| {
1474 (
1475 node.needs_measure(),
1476 node.needs_semantics(),
1477 node.cache_handles().epoch(),
1478 )
1479 }) {
1480 Ok(tuple) => tuple,
1481 Err(NodeError::TypeMismatch { .. }) => {
1482 let node = applier.get_mut(root)?;
1483 let measure_dirty = node.needs_measure();
1484 let semantics_dirty = node.needs_semantics();
1485 (measure_dirty, semantics_dirty, 0)
1486 }
1487 Err(err) => return Err(err),
1488 };
1489
1490 let epoch = if needs_remeasure {
1491 crate::render_state::next_layout_cache_epoch()
1492 } else if cached_epoch != 0 {
1493 cached_epoch
1494 } else {
1495 crate::render_state::current_layout_cache_epoch()
1496 };
1497
1498 let guard = ApplierSlotGuard::new(applier);
1499 let applier_host = guard.host();
1500 let slots_handle = guard.slots_handle();
1501 let after_guard = Instant::now();
1502
1503 let frame_arena = crate::render_state::take_layout_frame_arena();
1504 let mut builder = LayoutBuilder::new_with_epoch(
1505 Rc::clone(&applier_host),
1506 epoch,
1507 Rc::clone(&slots_handle),
1508 frame_arena,
1509 );
1510 let after_builder = Instant::now();
1511
1512 let measured = builder.measure_node(root, normalize_constraints(constraints))?;
1513 let after_measure = Instant::now();
1514
1515 if let Ok(mut applier) = applier_host.try_borrow_typed()
1516 && applier
1517 .with_node::<LayoutNode, _>(root, |node| {
1518 node.set_position(Point::default());
1519 })
1520 .is_err()
1521 {
1522 let _ = applier.with_node::<SubcomposeLayoutNode, _>(root, |node| {
1523 node.set_position(Point::default());
1524 });
1525 }
1526 let after_root_place = Instant::now();
1527
1528 let (layout_tree, semantics) = {
1529 let mut applier_ref = applier_host.borrow_typed();
1530 let layout_tree = if options.build_layout_tree {
1531 Some(build_layout_tree(&mut applier_ref, &measured)?)
1532 } else {
1533 None
1534 };
1535 let semantics = if options.collect_semantics {
1536 let semantics_tree = if let Some(layout_tree) = layout_tree.as_ref() {
1537 clear_semantics_dirty_flags(&mut applier_ref, &measured)?;
1538 build_semantics_tree_from_layout_tree(layout_tree)
1539 } else {
1540 build_semantics_tree_from_live_nodes(&mut applier_ref, &measured)?
1541 };
1542 Some(semantics_tree)
1543 } else {
1544 None
1545 };
1546 (layout_tree, semantics)
1547 };
1548 let after_aux = Instant::now();
1549
1550 drop(builder);
1551 let after_builder_drop = Instant::now();
1552
1553 drop(guard);
1554 let after_guard_drop = Instant::now();
1555
1556 log_layout_measure_telemetry(LayoutMeasureTelemetry {
1557 root,
1558 start: telemetry_start,
1559 after_repasses,
1560 after_guard,
1561 after_builder,
1562 after_measure,
1563 after_root_place,
1564 after_aux,
1565 after_builder_drop,
1566 after_guard_drop,
1567 });
1568
1569 Ok(LayoutMeasurements::new(measured, semantics, layout_tree))
1570}
1571
1572fn process_pending_layout_repasses(
1573 applier: &mut MemoryApplier,
1574 root: NodeId,
1575) -> Result<(), NodeError> {
1576 for node_id in crate::render_state::take_modifier_slice_repass_nodes() {
1577 if let Ok(node) = applier.get_mut(node_id) {
1578 let any = node.as_any_mut();
1579 if let Some(layout) = any.downcast_mut::<crate::widgets::nodes::LayoutNode>() {
1580 layout.mark_modifier_slices_dirty();
1581 } else if let Some(subcompose) =
1582 any.downcast_mut::<crate::subcompose_layout::SubcomposeLayoutNode>()
1583 {
1584 subcompose.mark_modifier_slices_dirty();
1585 }
1586 }
1587 }
1588 let measure_repass_nodes = crate::take_measure_repass_nodes();
1589 let repass_nodes = crate::take_layout_repass_nodes();
1590 if measure_repass_nodes.is_empty() && repass_nodes.is_empty() {
1591 return Ok(());
1592 }
1593 for node_id in measure_repass_nodes {
1594 cranpose_core::bubble_measure_dirty(applier as &mut dyn Applier, node_id);
1595 }
1596 for node_id in repass_nodes {
1597 cranpose_core::bubble_layout_dirty(applier as &mut dyn Applier, node_id);
1598 }
1599 applier.get_mut(root)?.mark_needs_layout();
1600 Ok(())
1601}
1602
1603struct LayoutBuilder {
1604 state: Rc<RefCell<LayoutBuilderState>>,
1605}
1606
1607impl LayoutBuilder {
1608 fn new_with_epoch(
1609 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1610 epoch: u64,
1611 slots: Rc<RefCell<SlotTable>>,
1612 frame_arena: FrameLayoutArena,
1613 ) -> Self {
1614 Self {
1615 state: Rc::new(RefCell::new(LayoutBuilderState::new_with_epoch(
1616 applier,
1617 epoch,
1618 slots,
1619 frame_arena,
1620 ))),
1621 }
1622 }
1623
1624 fn measure_node(
1625 &mut self,
1626 node_id: NodeId,
1627 constraints: Constraints,
1628 ) -> Result<Rc<MeasuredNode>, NodeError> {
1629 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
1630 }
1631
1632 fn set_runtime_handle(&mut self, handle: Option<RuntimeHandle>) {
1633 self.state.borrow_mut().runtime_handle = handle;
1634 }
1635}
1636
1637impl Drop for LayoutBuilder {
1638 fn drop(&mut self) {
1639 if Rc::strong_count(&self.state) != 1 {
1640 return;
1641 }
1642 let Ok(mut state) = self.state.try_borrow_mut() else {
1643 return;
1644 };
1645 crate::render_state::replace_layout_frame_arena(std::mem::take(&mut state.frame_arena));
1646 }
1647}
1648
1649struct LayoutBuilderState {
1650 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1651 runtime_handle: Option<RuntimeHandle>,
1652 slots: Rc<RefCell<SlotTable>>,
1653 cache_epoch: u64,
1654 cache_floor: u64,
1655 frame_arena: FrameLayoutArena,
1656}
1657
1658struct LayoutRuntimeFrameBindingCleanup {
1659 state: Rc<RefCell<LayoutRuntimeState>>,
1660}
1661
1662impl LayoutRuntimeFrameBindingCleanup {
1663 fn new(state: Rc<RefCell<LayoutRuntimeState>>) -> Self {
1664 Self { state }
1665 }
1666}
1667
1668impl Drop for LayoutRuntimeFrameBindingCleanup {
1669 fn drop(&mut self) {
1670 self.state.borrow().clear_frame_bindings();
1671 }
1672}
1673
1674impl LayoutBuilderState {
1675 fn new_with_epoch(
1676 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1677 epoch: u64,
1678 slots: Rc<RefCell<SlotTable>>,
1679 frame_arena: FrameLayoutArena,
1680 ) -> Self {
1681 let runtime_handle = applier.borrow_typed().runtime_handle();
1682
1683 Self {
1684 applier,
1685 runtime_handle,
1686 slots,
1687 cache_epoch: epoch,
1688 cache_floor: crate::render_state::layout_cache_floor(),
1689 frame_arena,
1690 }
1691 }
1692
1693 fn try_with_applier_result<R>(
1694 state_rc: &Rc<RefCell<Self>>,
1695 f: impl FnOnce(&mut MemoryApplier) -> Result<R, NodeError>,
1696 ) -> Option<Result<R, NodeError>> {
1697 let host = {
1698 let state = state_rc.borrow();
1699 Rc::clone(&state.applier)
1700 };
1701
1702 let Ok(mut applier) = host.try_borrow_typed() else {
1703 return None;
1704 };
1705
1706 Some(f(&mut applier))
1707 }
1708
1709 fn with_applier_result<R>(
1710 state_rc: &Rc<RefCell<Self>>,
1711 f: impl FnOnce(&mut MemoryApplier) -> Result<R, NodeError>,
1712 ) -> Result<R, NodeError> {
1713 Self::try_with_applier_result(state_rc, f).unwrap_or_else(|| {
1714 Err(NodeError::MissingContext {
1715 id: NodeId::default(),
1716 reason: "applier already borrowed",
1717 })
1718 })
1719 }
1720
1721 fn clear_node_placed(state_rc: &Rc<RefCell<Self>>, node_id: NodeId) {
1722 let host = {
1723 let state = state_rc.borrow();
1724 Rc::clone(&state.applier)
1725 };
1726 let Ok(mut applier) = host.try_borrow_typed() else {
1727 return;
1728 };
1729 if applier
1730 .with_node::<LayoutNode, _>(node_id, |node| {
1731 node.clear_placed();
1732 })
1733 .is_err()
1734 {
1735 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1736 node.clear_placed();
1737 });
1738 }
1739 }
1740
1741 fn measure_node(
1742 state_rc: Rc<RefCell<Self>>,
1743 node_id: NodeId,
1744 constraints: Constraints,
1745 ) -> Result<Rc<MeasuredNode>, NodeError> {
1746 let telemetry_start = Instant::now();
1747 Self::clear_node_placed(&state_rc, node_id);
1748
1749 if let Some(subcompose) =
1750 Self::try_measure_subcompose(Rc::clone(&state_rc), node_id, constraints)?
1751 {
1752 log_node_measure_telemetry(
1753 "subcompose",
1754 node_id,
1755 constraints,
1756 subcompose.size,
1757 subcompose.children.len(),
1758 telemetry_start,
1759 );
1760 return Ok(subcompose);
1761 }
1762
1763 if let Some(result) = Self::try_with_applier_result(&state_rc, |applier| {
1764 match applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1765 LayoutNodeSnapshot::from_layout_node(layout_node)
1766 }) {
1767 Ok(snapshot) => Ok(Some(snapshot)),
1768 Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => Ok(None),
1769 Err(err) => Err(err),
1770 }
1771 }) && let Some(snapshot) = result?
1772 {
1773 let measured =
1774 Self::measure_layout_node(Rc::clone(&state_rc), node_id, snapshot, constraints)?;
1775 log_node_measure_telemetry(
1776 "layout",
1777 node_id,
1778 constraints,
1779 measured.size,
1780 measured.children.len(),
1781 telemetry_start,
1782 );
1783 return Ok(measured);
1784 }
1785
1786 let measured = Rc::new(MeasuredNode::new(
1787 node_id,
1788 Size::default(),
1789 Point { x: 0.0, y: 0.0 },
1790 Point::default(),
1791 Vec::new(),
1792 ));
1793 log_node_measure_telemetry(
1794 "fallback",
1795 node_id,
1796 constraints,
1797 measured.size,
1798 measured.children.len(),
1799 telemetry_start,
1800 );
1801 Ok(measured)
1802 }
1803
1804 fn cached_measure_node_with_applier(
1805 applier: &mut MemoryApplier,
1806 node_id: NodeId,
1807 constraints: Constraints,
1808 ) -> Result<Option<Rc<MeasuredNode>>, NodeError> {
1809 let Some(data) = Self::layout_child_measure_data(applier, node_id)? else {
1810 return Ok(None);
1811 };
1812 if data.needs_measure
1813 || data.needs_layout
1814 || data.cache.epoch() == 0
1815 || data.cache.epoch() != crate::render_state::current_layout_cache_epoch()
1816 {
1817 return Ok(None);
1818 }
1819
1820 let Some(measured) = data.cache.get_measurement(constraints) else {
1821 return Ok(None);
1822 };
1823
1824 if let Some(layout_state) = data.layout_state {
1825 let mut layout_state = layout_state.borrow_mut();
1826 layout_state.set_size(measured.size);
1827 } else {
1828 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1829 node.set_measured_size(measured.size);
1830 });
1831 }
1832
1833 Ok(Some(measured))
1834 }
1835
1836 fn try_measure_subcompose(
1837 state_rc: Rc<RefCell<Self>>,
1838 node_id: NodeId,
1839 constraints: Constraints,
1840 ) -> Result<Option<Rc<MeasuredNode>>, NodeError> {
1841 let applier_host = {
1842 let state = state_rc.borrow();
1843 Rc::clone(&state.applier)
1844 };
1845
1846 let (node_handle, resolved_modifiers) = {
1847 let Ok(mut applier) = applier_host.try_borrow_typed() else {
1848 return Ok(None);
1849 };
1850 let node = match applier.get_mut(node_id) {
1851 Ok(node) => node,
1852 Err(NodeError::Missing { .. }) => return Ok(None),
1853 Err(err) => return Err(err),
1854 };
1855 let any = node.as_any_mut();
1856 if let Some(subcompose) =
1857 any.downcast_mut::<crate::subcompose_layout::SubcomposeLayoutNode>()
1858 {
1859 let handle = subcompose.handle();
1860 let resolved_modifiers = handle
1861 .resolved_modifiers()
1862 .on_device_grid(subcompose.density().density());
1863 (handle, resolved_modifiers)
1864 } else {
1865 return Ok(None);
1866 }
1867 };
1868
1869 let runtime_handle = {
1870 let mut state = state_rc.borrow_mut();
1871 if state.runtime_handle.is_none()
1872 && let Ok(applier) = applier_host.try_borrow_typed()
1873 {
1874 state.runtime_handle = applier.runtime_handle();
1875 }
1876 state
1877 .runtime_handle
1878 .clone()
1879 .ok_or(NodeError::MissingContext {
1880 id: node_id,
1881 reason: "runtime handle required for subcomposition",
1882 })?
1883 };
1884
1885 let props = resolved_modifiers.layout_properties();
1886 let padding = resolved_modifiers.padding();
1887 let offset = resolved_modifiers.offset();
1888 let mut inner_constraints = normalize_constraints(subtract_padding(constraints, padding));
1889
1890 if let DimensionConstraint::Points(width) = props.width() {
1891 let constrained_width = width - padding.horizontal_sum();
1892 inner_constraints.max_width = inner_constraints.max_width.min(constrained_width);
1893 inner_constraints.min_width = inner_constraints.min_width.min(constrained_width);
1894 }
1895 if let DimensionConstraint::Points(height) = props.height() {
1896 let constrained_height = height - padding.vertical_sum();
1897 inner_constraints.max_height = inner_constraints.max_height.min(constrained_height);
1898 inner_constraints.min_height = inner_constraints.min_height.min(constrained_height);
1899 }
1900
1901 let mut slots_guard = SlotsGuard::take(Rc::clone(&state_rc));
1902 let slots_host = slots_guard.host();
1903 let applier_host_dyn: Rc<dyn ApplierHost> = applier_host.clone();
1904 let observer = SnapshotStateObserver::new(|callback| callback());
1905 let composer = Composer::new(
1906 Rc::clone(&slots_host),
1907 applier_host_dyn,
1908 runtime_handle,
1909 observer,
1910 Some(node_id),
1911 );
1912 composer.enter_phase(Phase::Measure);
1913
1914 let state_rc_clone = Rc::clone(&state_rc);
1915 let measure_error = RefCell::new(None);
1916 let state_rc_for_subcompose = Rc::clone(&state_rc_clone);
1917 let error_for_subcompose = &measure_error;
1918 let measured_children = node_handle.measured_children_scratch();
1919 let measured_children_for_subcompose = Rc::clone(&measured_children);
1920 let state_rc_for_cached = Rc::clone(&state_rc_clone);
1921 let error_for_cached = &measure_error;
1922 let measured_children_for_cached = Rc::clone(&measured_children);
1923 let measured_children_for_lookup = Rc::clone(&measured_children);
1924 let measured_children_for_retained = Rc::clone(&measured_children);
1925
1926 let measure_result = node_handle.measure_with_cached_batch(
1927 &composer,
1928 node_id,
1929 inner_constraints,
1930 CachedBatchMeasureInputs {
1931 measurer: Box::new(
1932 move |child_id: NodeId, child_constraints: Constraints| -> Size {
1933 match Self::measure_node(
1934 Rc::clone(&state_rc_for_subcompose),
1935 child_id,
1936 child_constraints,
1937 ) {
1938 Ok(measured) => {
1939 measured_children_for_subcompose
1940 .borrow_mut()
1941 .insert(child_id, Rc::clone(&measured));
1942 measured.size
1943 }
1944 Err(err) => {
1945 let mut slot = error_for_subcompose.borrow_mut();
1946 if slot.is_none() {
1947 *slot = Some(err);
1948 }
1949 Size::default()
1950 }
1951 }
1952 },
1953 ),
1954 cached_measure_batch_registrar: Box::new(
1955 move |child_ids: &[NodeId],
1956 child_constraints: Constraints,
1957 out: &mut Vec<Option<Size>>| {
1958 out.clear();
1959 out.resize(child_ids.len(), None);
1960
1961 let applier_host = {
1962 let state = state_rc_for_cached.borrow();
1963 Rc::clone(&state.applier)
1964 };
1965 let Ok(mut applier) = applier_host.try_borrow_typed() else {
1966 return;
1967 };
1968
1969 let mut measured_children = measured_children_for_cached.borrow_mut();
1970 for (index, &child_id) in child_ids.iter().enumerate() {
1971 match Self::cached_measure_node_with_applier(
1972 &mut applier,
1973 child_id,
1974 child_constraints,
1975 ) {
1976 Ok(Some(measured)) => {
1977 out[index] = Some(measured.size);
1978 measured_children.insert(child_id, Rc::clone(&measured));
1979 }
1980 Ok(None) => {}
1981 Err(err) => {
1982 let mut slot = error_for_cached.borrow_mut();
1983 if slot.is_none() {
1984 *slot = Some(err);
1985 }
1986 break;
1987 }
1988 }
1989 }
1990 },
1991 ),
1992 retained_measure_lookup: Box::new(move |child_id| {
1993 measured_children_for_lookup
1994 .borrow()
1995 .get(&child_id)
1996 .cloned()
1997 }),
1998 retained_measure_registrar: Box::new(move |measurements| {
1999 let mut measured_children = measured_children_for_retained.borrow_mut();
2000 for measured in measurements {
2001 measured_children.insert(measured.node_id(), Rc::clone(measured));
2002 }
2003 }),
2004 error: &measure_error,
2005 },
2006 )?;
2007 drop(composer);
2008 slots_guard.restore(slots_host.into_table()?);
2009
2010 if let Some(err) = measure_error.borrow_mut().take() {
2011 return Err(err);
2012 }
2013
2014 let cranpose_ui_layout::MeasureResult {
2015 size: measured_size,
2016 placements,
2017 } = measure_result;
2018
2019 let mut width = measured_size.width + padding.horizontal_sum();
2020 let mut height = measured_size.height + padding.vertical_sum();
2021
2022 width = resolve_dimension(
2023 width,
2024 props.width(),
2025 props.min_width(),
2026 props.max_width(),
2027 constraints.min_width,
2028 constraints.max_width,
2029 );
2030 height = resolve_dimension(
2031 height,
2032 props.height(),
2033 props.min_height(),
2034 props.max_height(),
2035 constraints.min_height,
2036 constraints.max_height,
2037 );
2038
2039 let mut children = Vec::with_capacity(placements.len());
2040 let mut measured_children_by_id = measured_children.borrow_mut();
2041
2042 if let Ok(mut applier) = applier_host.try_borrow_typed() {
2043 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |parent_node| {
2044 parent_node.set_measured_size(Size { width, height });
2045 parent_node.clear_needs_measure();
2046 parent_node.clear_needs_layout();
2047 });
2048 }
2049
2050 for placement in &placements {
2051 let child = if let Some(measured) = measured_children_by_id.remove(&placement.node_id) {
2052 measured
2053 } else {
2054 Self::measure_node(Rc::clone(&state_rc), placement.node_id, inner_constraints)?
2055 };
2056 let policy_position = Point {
2057 x: padding.left + placement.x,
2058 y: padding.top + placement.y,
2059 };
2060 let retained_position = Point {
2061 x: policy_position.x + child.offset.x,
2062 y: policy_position.y + child.offset.y,
2063 };
2064
2065 if let Ok(mut applier) = applier_host.try_borrow_typed()
2066 && applier
2067 .with_node::<LayoutNode, _>(placement.node_id, |node| {
2068 node.set_position(retained_position);
2069 })
2070 .is_err()
2071 {
2072 let _ = applier.with_node::<SubcomposeLayoutNode, _>(placement.node_id, |node| {
2073 node.set_position(retained_position);
2074 });
2075 }
2076
2077 children.push(MeasuredChild {
2078 node: child,
2079 offset: policy_position,
2080 });
2081 }
2082
2083 node_handle.set_active_children(children.iter().map(|c| c.node.node_id));
2084 node_handle.recycle_placement_scratch(placements);
2085
2086 Ok(Some(Rc::new(MeasuredNode::new(
2087 node_id,
2088 Size { width, height },
2089 offset,
2090 Point::default(),
2091 children,
2092 ))))
2093 }
2094 fn measure_through_modifier_chain(
2095 state_rc: &Rc<RefCell<Self>>,
2096 node_id: NodeId,
2097 runtime_state: &mut LayoutRuntimeState,
2098 measure_policy: &Rc<dyn MeasurePolicy>,
2099 constraints: Constraints,
2100 layout_node_data: &mut Vec<LayoutModifierNodeData>,
2101 placements: &mut Vec<Placement>,
2102 ) -> ModifierChainMeasurement {
2103 use cranpose_foundation::NodeCapabilities;
2104
2105 layout_node_data.clear();
2106 let mut offset = Point::default();
2107 let mut density = crate::density::Density::default();
2108 let mut window_root = false;
2109 let mut geometry = None;
2110
2111 {
2112 let state = state_rc.borrow();
2113 let mut applier = state.applier.borrow_typed();
2114
2115 let _ = applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
2116 density = layout_node.density();
2117 window_root = layout_node.is_window_root();
2118 geometry = Some(layout_node.coordinator_geometry());
2119 let chain_handle = layout_node.modifier_chain();
2120
2121 if !chain_handle.has_layout_nodes() {
2122 return;
2123 }
2124
2125 chain_handle.chain().for_each_forward_matching(
2126 NodeCapabilities::LAYOUT,
2127 |node_ref| {
2128 if let Some(index) = node_ref.entry_index() {
2129 if let Some(node_rc) = chain_handle.chain().get_node_rc(index) {
2130 layout_node_data.push((index, Rc::clone(&node_rc)));
2131 }
2132
2133 node_ref.with_node(|node| {
2134 if let Some(offset_node) =
2135 node.as_any()
2136 .downcast_ref::<crate::modifier_nodes::OffsetNode>()
2137 {
2138 let delta = offset_node.device_offset(density.density());
2139 offset.x += delta.x;
2140 offset.y += delta.y;
2141 }
2142 });
2143 }
2144 },
2145 );
2146 });
2147 }
2148
2149 let scope = crate::density::DensityMeasureScope::new(density);
2150
2151 if layout_node_data.is_empty() {
2152 let final_size = measure_policy.measure_into(
2153 &scope,
2154 runtime_state.child_measurables(),
2155 constraints,
2156 placements,
2157 );
2158 write_node_geometry(geometry.as_deref(), node_id, |geometry| {
2159 geometry.replace([GeometryRect {
2160 x: 0.0,
2161 y: 0.0,
2162 width: final_size.width,
2163 height: final_size.height,
2164 }])
2165 });
2166
2167 return ModifierChainMeasurement {
2168 size: final_size,
2169 content_offset: Point::default(),
2170 offset,
2171 window_root,
2172 };
2173 }
2174
2175 runtime_state.reconcile_coordinator_chain(layout_node_data.as_slice());
2176 let frame = CoordinatorFrame::new(
2177 measure_policy,
2178 &scope,
2179 runtime_state.child_measurables(),
2180 placements,
2181 );
2182
2183 let placeable = runtime_state
2184 .coordinator_chain()
2185 .measure_from(0, &frame, constraints);
2186 let final_size = Size {
2187 width: placeable.width(),
2188 height: placeable.height(),
2189 };
2190
2191 write_node_geometry(geometry.as_deref(), node_id, |geometry| {
2192 runtime_state
2193 .coordinator_chain()
2194 .write_geometry(geometry, offset)
2195 });
2196
2197 let content_offset = placeable.content_offset();
2198 let all_placement_offset = Point {
2199 x: content_offset.0,
2200 y: content_offset.1,
2201 };
2202
2203 let content_offset = Point {
2204 x: all_placement_offset.x - offset.x,
2205 y: all_placement_offset.y - offset.y,
2206 };
2207
2208 let invalidations = frame.take_invalidations();
2209 if !invalidations.is_empty() {
2210 Self::with_applier_result(state_rc, |applier| {
2211 applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
2212 for kind in invalidations {
2213 match kind {
2214 InvalidationKind::Layout => layout_node.mark_needs_measure(),
2215 InvalidationKind::Draw => layout_node.mark_needs_redraw(),
2216 InvalidationKind::Semantics => layout_node.mark_needs_semantics(),
2217 InvalidationKind::PointerInput => layout_node.mark_needs_pointer_pass(),
2218 InvalidationKind::Focus => layout_node.mark_needs_focus_sync(),
2219 }
2220 }
2221 })
2222 })
2223 .ok();
2224 }
2225
2226 ModifierChainMeasurement {
2227 size: final_size,
2228 content_offset,
2229 offset,
2230 window_root,
2231 }
2232 }
2233
2234 fn layout_child_measure_data(
2235 applier: &mut MemoryApplier,
2236 child_id: NodeId,
2237 ) -> Result<Option<LayoutChildMeasureData>, NodeError> {
2238 match applier.with_node::<LayoutNode, _>(child_id, |n| LayoutChildMeasureData {
2239 cache: n.cache_handles(),
2240 layout_state: Some(n.layout_state_handle()),
2241 needs_layout: n.needs_layout(),
2242 needs_measure: n.needs_measure(),
2243 }) {
2244 Ok(data) => Ok(Some(data)),
2245 Err(NodeError::TypeMismatch { .. }) => {
2246 match applier.with_node::<SubcomposeLayoutNode, _>(child_id, |n| {
2247 LayoutChildMeasureData {
2248 cache: n.cache_handles(),
2249 layout_state: None,
2250 needs_layout: n.needs_layout(),
2251 needs_measure: n.needs_measure(),
2252 }
2253 }) {
2254 Ok(data) => Ok(Some(data)),
2255 Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => Ok(None),
2256 Err(err) => Err(err),
2257 }
2258 }
2259 Err(NodeError::Missing { .. }) => Ok(None),
2260 Err(err) => Err(err),
2261 }
2262 }
2263
2264 fn measure_layout_node(
2265 state_rc: Rc<RefCell<Self>>,
2266 node_id: NodeId,
2267 snapshot: LayoutNodeSnapshot,
2268 constraints: Constraints,
2269 ) -> Result<Rc<MeasuredNode>, NodeError> {
2270 let (cache_epoch, cache_floor) = {
2271 let state = state_rc.borrow();
2272 (state.cache_epoch, state.cache_floor)
2273 };
2274 let LayoutNodeSnapshot {
2275 measure_policy,
2276 cache,
2277 layout_runtime_state,
2278 needs_layout,
2279 needs_measure,
2280 } = snapshot;
2281 cache.activate(cache_epoch);
2282
2283 if !needs_measure
2284 && !needs_layout
2285 && let Some(cached) = cache.get_measurement(constraints)
2286 {
2287 Self::with_applier_result(&state_rc, |applier| {
2288 applier.with_node::<LayoutNode, _>(node_id, |node| {
2289 node.clear_needs_measure();
2290 node.clear_needs_layout();
2291 })
2292 })
2293 .ok();
2294 return Ok(cached);
2295 }
2296
2297 let (runtime_handle, applier_host) = {
2298 let state = state_rc.borrow();
2299 (state.runtime_handle.clone(), Rc::clone(&state.applier))
2300 };
2301
2302 let measure_handle = LayoutMeasureHandle::new(Rc::clone(&state_rc));
2303 let error = Rc::clone(&layout_runtime_state.borrow().error);
2304 error.borrow_mut().take();
2305 let mut pools = VecPools::acquire(Rc::clone(&state_rc));
2306 let (records, child_ids, layout_node_data, placements) = pools.parts();
2307
2308 applier_host
2309 .borrow_typed()
2310 .with_node::<LayoutNode, _>(node_id, |node| {
2311 child_ids.extend_from_slice(&node.children);
2312 })?;
2313
2314 let mut valid_child_count = 0;
2315 for index in 0..child_ids.len() {
2316 let child_id = child_ids[index];
2317 let child_exists = {
2318 let mut applier = applier_host.borrow_typed();
2319 Self::layout_child_measure_data(&mut applier, child_id)?.is_some()
2320 };
2321 if child_exists {
2322 child_ids[valid_child_count] = child_id;
2323 valid_child_count += 1;
2324 }
2325 }
2326 child_ids.truncate(valid_child_count);
2327
2328 let _frame_binding_cleanup =
2329 LayoutRuntimeFrameBindingCleanup::new(Rc::clone(&layout_runtime_state));
2330
2331 {
2332 let mut runtime_state = layout_runtime_state.borrow_mut();
2333 runtime_state.reconcile_child_measurables(child_ids.as_slice());
2334
2335 for (index, &child_id) in child_ids.iter().enumerate() {
2336 let data = {
2337 let mut applier = applier_host.borrow_typed();
2338 Self::layout_child_measure_data(&mut applier, child_id)?
2339 };
2340 let Some(data) = data else {
2341 continue;
2342 };
2343
2344 let child_is_stale = data.is_stale(cache_floor);
2345 let child_cache_epoch = if child_is_stale {
2346 cache_epoch
2347 } else {
2348 data.cache.epoch()
2349 };
2350 let child_state = runtime_state.child_state(index);
2351 child_state.configure(LayoutChildMeasureConfig {
2352 applier: Rc::clone(&applier_host),
2353 node_id: child_id,
2354 error: Rc::clone(&error),
2355 runtime_handle: runtime_handle.clone(),
2356 cache: data.cache,
2357 cache_epoch: child_cache_epoch,
2358 force_remeasure: child_is_stale,
2359 measure_handle: Some(measure_handle.clone()),
2360 layout_state: data.layout_state,
2361 });
2362 records.push((child_id, ChildRecord { state: child_state }));
2363 }
2364 }
2365
2366 let chain_constraints = constraints;
2367
2368 let modifier_chain_result = {
2369 let mut runtime_state = layout_runtime_state.borrow_mut();
2370 Self::measure_through_modifier_chain(
2371 &state_rc,
2372 node_id,
2373 &mut runtime_state,
2374 &measure_policy,
2375 chain_constraints,
2376 layout_node_data,
2377 placements,
2378 )
2379 };
2380
2381 let (width, height, content_offset, offset, window_root) = {
2382 let result = modifier_chain_result;
2383 if let Some(err) = error.borrow_mut().take() {
2384 return Err(err);
2385 }
2386
2387 (
2388 result.size.width,
2389 result.size.height,
2390 result.content_offset,
2391 result.offset,
2392 result.window_root,
2393 )
2394 };
2395
2396 let mut measured_children = Vec::with_capacity(records.len());
2397 for (child_id, record) in records.iter() {
2398 if let Some(measured) = record.state.take_measured() {
2399 let placed = placements
2400 .iter()
2401 .find(|placement| placement.node_id == *child_id)
2402 .map(|placement| Point {
2403 x: placement.x,
2404 y: placement.y,
2405 });
2406 if let Some(raw) = placed {
2407 record.state.place_retained(Point {
2408 x: raw.x + measured.offset.x,
2409 y: raw.y + measured.offset.y,
2410 });
2411 }
2412 let base_position = placed
2413 .or_else(|| record.state.last_position())
2414 .unwrap_or(Point { x: 0.0, y: 0.0 });
2415 let position = Point {
2416 x: content_offset.x + base_position.x,
2417 y: content_offset.y + base_position.y,
2418 };
2419 measured_children.push(MeasuredChild {
2420 node: measured,
2421 offset: position,
2422 });
2423 }
2424 }
2425
2426 let measured = Rc::new(
2427 MeasuredNode::new(
2428 node_id,
2429 Size { width, height },
2430 offset,
2431 content_offset,
2432 measured_children,
2433 )
2434 .with_window_root(window_root),
2435 );
2436
2437 cache.store_measurement(constraints, Rc::clone(&measured));
2438
2439 Self::with_applier_result(&state_rc, |applier| {
2440 applier.with_node::<LayoutNode, _>(node_id, |node| {
2441 node.clear_needs_measure();
2442 node.clear_needs_layout();
2443 node.set_measured_size(Size { width, height });
2444 node.set_content_offset(content_offset);
2445 })
2446 })
2447 .ok();
2448
2449 Ok(measured)
2450 }
2451}
2452
2453struct LayoutChildMeasureData {
2454 cache: LayoutNodeCacheHandles,
2455 layout_state: Option<Rc<RefCell<LayoutState>>>,
2456 needs_layout: bool,
2457 needs_measure: bool,
2458}
2459
2460impl LayoutChildMeasureData {
2461 fn is_stale(&self, cache_floor: u64) -> bool {
2462 self.needs_layout || self.needs_measure || self.cache.epoch() < cache_floor
2463 }
2464}
2465
2466struct LayoutNodeSnapshot {
2467 measure_policy: Rc<dyn MeasurePolicy>,
2468 cache: LayoutNodeCacheHandles,
2469 layout_runtime_state: Rc<RefCell<LayoutRuntimeState>>,
2470 needs_layout: bool,
2471 needs_measure: bool,
2472}
2473
2474impl LayoutNodeSnapshot {
2475 fn from_layout_node(node: &LayoutNode) -> Self {
2476 Self {
2477 measure_policy: Rc::clone(&node.measure_policy),
2478 cache: node.cache_handles(),
2479 layout_runtime_state: node.layout_runtime_state_handle(),
2480 needs_layout: node.needs_layout(),
2481 needs_measure: node.needs_measure(),
2482 }
2483 }
2484}
2485
2486struct VecPools {
2487 state: Rc<RefCell<LayoutBuilderState>>,
2488 records: Vec<(NodeId, ChildRecord)>,
2489 child_ids: Vec<NodeId>,
2490 layout_node_data: Vec<LayoutModifierNodeData>,
2491 placements: Vec<Placement>,
2492}
2493
2494impl VecPools {
2495 fn acquire(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
2496 let (records, child_ids, layout_node_data, placements) = {
2497 let mut state_mut = state.borrow_mut();
2498 (
2499 state_mut.frame_arena.tmp_records.acquire(),
2500 state_mut.frame_arena.tmp_child_ids.acquire(),
2501 state_mut.frame_arena.tmp_layout_node_data.acquire(),
2502 state_mut.frame_arena.tmp_placements.acquire(),
2503 )
2504 };
2505 Self {
2506 state,
2507 records,
2508 child_ids,
2509 layout_node_data,
2510 placements,
2511 }
2512 }
2513
2514 #[expect(clippy::type_complexity)]
2515 fn parts(
2516 &mut self,
2517 ) -> (
2518 &mut Vec<(NodeId, ChildRecord)>,
2519 &mut Vec<NodeId>,
2520 &mut Vec<LayoutModifierNodeData>,
2521 &mut Vec<Placement>,
2522 ) {
2523 (
2524 &mut self.records,
2525 &mut self.child_ids,
2526 &mut self.layout_node_data,
2527 &mut self.placements,
2528 )
2529 }
2530}
2531
2532impl Drop for VecPools {
2533 fn drop(&mut self) {
2534 let mut state = self.state.borrow_mut();
2535 state
2536 .frame_arena
2537 .tmp_records
2538 .release(std::mem::take(&mut self.records));
2539 state
2540 .frame_arena
2541 .tmp_child_ids
2542 .release(std::mem::take(&mut self.child_ids));
2543 state
2544 .frame_arena
2545 .tmp_layout_node_data
2546 .release(std::mem::take(&mut self.layout_node_data));
2547 state
2548 .frame_arena
2549 .tmp_placements
2550 .release(std::mem::take(&mut self.placements));
2551 }
2552}
2553
2554struct SlotsGuard {
2555 state: Rc<RefCell<LayoutBuilderState>>,
2556 slots: Option<SlotTable>,
2557}
2558
2559impl SlotsGuard {
2560 fn take(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
2561 let slots = {
2562 let state_ref = state.borrow();
2563 let mut slots_ref = state_ref.slots.borrow_mut();
2564 std::mem::take(&mut *slots_ref)
2565 };
2566 Self {
2567 state,
2568 slots: Some(slots),
2569 }
2570 }
2571
2572 fn host(&mut self) -> Rc<SlotsHost> {
2573 let slots = self.slots.take().unwrap_or_default();
2574 Rc::new(SlotsHost::new(slots))
2575 }
2576
2577 fn restore(&mut self, slots: SlotTable) {
2578 debug_assert!(self.slots.is_none());
2579 self.slots = Some(slots);
2580 }
2581}
2582
2583impl Drop for SlotsGuard {
2584 fn drop(&mut self) {
2585 if let Some(slots) = self.slots.take() {
2586 let state_ref = self.state.borrow();
2587 *state_ref.slots.borrow_mut() = slots;
2588 }
2589 }
2590}
2591
2592#[derive(Clone)]
2593struct LayoutMeasureHandle {
2594 state: Rc<RefCell<LayoutBuilderState>>,
2595}
2596
2597impl LayoutMeasureHandle {
2598 fn new(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
2599 Self { state }
2600 }
2601
2602 fn measure(
2603 &self,
2604 node_id: NodeId,
2605 constraints: Constraints,
2606 ) -> Result<Rc<MeasuredNode>, NodeError> {
2607 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
2608 }
2609}
2610
2611#[derive(Debug, Clone)]
2612pub(crate) struct MeasuredNode {
2613 node_id: NodeId,
2614 size: Size,
2615 offset: Point,
2616 content_offset: Point,
2617 children: Vec<MeasuredChild>,
2618 window_root: bool,
2619}
2620
2621impl MeasuredNode {
2622 fn new(
2623 node_id: NodeId,
2624 size: Size,
2625 offset: Point,
2626 content_offset: Point,
2627 children: Vec<MeasuredChild>,
2628 ) -> Self {
2629 Self {
2630 node_id,
2631 size,
2632 offset,
2633 content_offset,
2634 children,
2635 window_root: false,
2636 }
2637 }
2638
2639 fn with_window_root(mut self, window_root: bool) -> Self {
2640 self.window_root = window_root;
2641 self
2642 }
2643
2644 pub(crate) fn size_for_parent(&self) -> Size {
2645 if self.window_root {
2646 Size::new(0.0, 0.0)
2647 } else {
2648 self.size
2649 }
2650 }
2651
2652 #[cfg(test)]
2653 pub(crate) fn leaf(node_id: NodeId, size: Size) -> Self {
2654 Self::new(
2655 node_id,
2656 size,
2657 Point::default(),
2658 Point::default(),
2659 Vec::new(),
2660 )
2661 }
2662
2663 pub(crate) fn node_id(&self) -> NodeId {
2664 self.node_id
2665 }
2666
2667 pub(crate) fn size(&self) -> Size {
2668 self.size
2669 }
2670}
2671
2672#[derive(Debug, Clone)]
2673struct MeasuredChild {
2674 node: Rc<MeasuredNode>,
2675 offset: Point,
2676}
2677
2678struct ChildRecord {
2679 state: Rc<LayoutChildMeasureState>,
2680}
2681
2682struct CoordinatorFrame<'a> {
2683 measure_policy: &'a Rc<dyn MeasurePolicy>,
2684 scope: &'a dyn cranpose_ui_layout::MeasureScope,
2685 measurables: &'a [Box<dyn Measurable>],
2686 placements: RefCell<&'a mut Vec<Placement>>,
2687 context: RefCell<LayoutNodeContext>,
2688}
2689
2690impl<'a> CoordinatorFrame<'a> {
2691 fn new(
2692 measure_policy: &'a Rc<dyn MeasurePolicy>,
2693 scope: &'a dyn cranpose_ui_layout::MeasureScope,
2694 measurables: &'a [Box<dyn Measurable>],
2695 placements: &'a mut Vec<Placement>,
2696 ) -> Self {
2697 Self {
2698 measure_policy,
2699 scope,
2700 measurables,
2701 placements: RefCell::new(placements),
2702 context: RefCell::new(LayoutNodeContext::new(scope.density())),
2703 }
2704 }
2705
2706 fn take_invalidations(&self) -> Vec<InvalidationKind> {
2707 self.context.borrow_mut().take_invalidations()
2708 }
2709}
2710
2711struct CoordinatorLink<'chain, 'frame_ref, 'frame_data> {
2712 chain: &'chain CoordinatorChain,
2713 frame: &'frame_ref CoordinatorFrame<'frame_data>,
2714 index: usize,
2715}
2716
2717impl Measurable for CoordinatorLink<'_, '_, '_> {
2718 fn measure(&self, constraints: Constraints) -> Placeable {
2719 self.chain.measure_from(self.index, self.frame, constraints)
2720 }
2721
2722 fn min_intrinsic_width(&self, height: f32) -> f32 {
2723 self.chain
2724 .min_intrinsic_width_from(self.index, self.frame, height)
2725 }
2726
2727 fn max_intrinsic_width(&self, height: f32) -> f32 {
2728 self.chain
2729 .max_intrinsic_width_from(self.index, self.frame, height)
2730 }
2731
2732 fn min_intrinsic_height(&self, width: f32) -> f32 {
2733 self.chain
2734 .min_intrinsic_height_from(self.index, self.frame, width)
2735 }
2736
2737 fn max_intrinsic_height(&self, width: f32) -> f32 {
2738 self.chain
2739 .max_intrinsic_height_from(self.index, self.frame, width)
2740 }
2741}
2742
2743struct CoordinatorNode {
2744 modifier_index: usize,
2745 node: Rc<RefCell<Box<dyn cranpose_foundation::ModifierNode>>>,
2746 measured_size: Cell<Size>,
2747 accumulated_offset: Cell<Point>,
2748}
2749
2750impl CoordinatorNode {
2751 fn new(
2752 modifier_index: usize,
2753 node: Rc<RefCell<Box<dyn cranpose_foundation::ModifierNode>>>,
2754 ) -> Self {
2755 Self {
2756 modifier_index,
2757 node,
2758 measured_size: Cell::new(Size::default()),
2759 accumulated_offset: Cell::new(Point::default()),
2760 }
2761 }
2762
2763 fn matches(
2764 &self,
2765 modifier_index: usize,
2766 node: &Rc<RefCell<Box<dyn cranpose_foundation::ModifierNode>>>,
2767 ) -> bool {
2768 self.modifier_index == modifier_index && Rc::ptr_eq(&self.node, node)
2769 }
2770
2771 #[cfg(test)]
2772 fn ptr(&self) -> usize {
2773 Rc::as_ptr(&self.node) as *const () as usize
2774 }
2775}
2776
2777#[derive(Default)]
2778struct CoordinatorChain {
2779 nodes: Vec<CoordinatorNode>,
2780 inner_size: Cell<Size>,
2782}
2783
2784impl CoordinatorChain {
2785 fn reconcile(&mut self, layout_node_data: &[LayoutModifierNodeData]) {
2786 if self.matches(layout_node_data) {
2787 return;
2788 }
2789
2790 let mut previous_nodes = std::mem::take(&mut self.nodes);
2791 self.nodes.reserve(layout_node_data.len());
2792
2793 for (modifier_index, node) in layout_node_data {
2794 if let Some(position) = previous_nodes
2795 .iter()
2796 .position(|candidate| candidate.matches(*modifier_index, node))
2797 {
2798 self.nodes.push(previous_nodes.swap_remove(position));
2799 } else {
2800 self.nodes
2801 .push(CoordinatorNode::new(*modifier_index, Rc::clone(node)));
2802 }
2803 }
2804 }
2805
2806 fn matches(&self, layout_node_data: &[LayoutModifierNodeData]) -> bool {
2807 self.nodes.len() == layout_node_data.len()
2808 && self
2809 .nodes
2810 .iter()
2811 .zip(layout_node_data.iter())
2812 .all(|(node, (modifier_index, node_rc))| node.matches(*modifier_index, node_rc))
2813 }
2814
2815 fn measure_from(
2816 &self,
2817 index: usize,
2818 frame: &CoordinatorFrame<'_>,
2819 constraints: Constraints,
2820 ) -> Placeable {
2821 let Some(node) = self.nodes.get(index) else {
2822 let mut placements = frame.placements.borrow_mut();
2823 let size = frame.measure_policy.measure_into(
2824 frame.scope,
2825 frame.measurables,
2826 constraints,
2827 &mut placements,
2828 );
2829 self.inner_size.set(size);
2830 return Placeable::value(size.width, size.height, NodeId::default());
2831 };
2832
2833 let wrapped = CoordinatorLink {
2834 chain: self,
2835 frame,
2836 index: index + 1,
2837 };
2838 let node_borrow = node.node.borrow();
2839
2840 let Some(layout_node) = node_borrow.as_layout_node() else {
2841 let placeable = wrapped.measure(constraints);
2842 node.measured_size.set(Size {
2843 width: placeable.width(),
2844 height: placeable.height(),
2845 });
2846 let child_accumulated = self.total_content_offset_from(index + 1);
2847 node.accumulated_offset.set(child_accumulated);
2848 return Placeable::value_with_offset(
2849 placeable.width(),
2850 placeable.height(),
2851 NodeId::default(),
2852 (child_accumulated.x, child_accumulated.y),
2853 );
2854 };
2855
2856 let result = match frame.context.try_borrow_mut() {
2857 Ok(mut context) => layout_node.measure(&mut *context, &wrapped, constraints),
2858 Err(_) => {
2859 let mut temp = LayoutNodeContext::new(frame.scope.density());
2860 let result = layout_node.measure(&mut temp, &wrapped, constraints);
2861 if let Ok(mut context) = frame.context.try_borrow_mut() {
2862 for kind in temp.take_invalidations() {
2863 context.invalidate(kind);
2864 }
2865 }
2866 result
2867 }
2868 };
2869
2870 node.measured_size.set(result.size);
2871 let local_offset = Point {
2872 x: result.placement_offset_x,
2873 y: result.placement_offset_y,
2874 };
2875 let child_accumulated = self.total_content_offset_from(index + 1);
2876 let accumulated = Point {
2877 x: local_offset.x + child_accumulated.x,
2878 y: local_offset.y + child_accumulated.y,
2879 };
2880 node.accumulated_offset.set(accumulated);
2881
2882 Placeable::value_with_offset(
2883 result.size.width,
2884 result.size.height,
2885 NodeId::default(),
2886 (accumulated.x, accumulated.y),
2887 )
2888 }
2889
2890 fn min_intrinsic_width_from(
2891 &self,
2892 index: usize,
2893 frame: &CoordinatorFrame<'_>,
2894 height: f32,
2895 ) -> f32 {
2896 let Some(node) = self.nodes.get(index) else {
2897 return frame
2898 .measure_policy
2899 .min_intrinsic_width(frame.measurables, height);
2900 };
2901 let wrapped = CoordinatorLink {
2902 chain: self,
2903 frame,
2904 index: index + 1,
2905 };
2906 let node_borrow = node.node.borrow();
2907 node_borrow.as_layout_node().map_or_else(
2908 || wrapped.min_intrinsic_width(height),
2909 |layout_node| layout_node.min_intrinsic_width(&wrapped, height, frame.scope.density()),
2910 )
2911 }
2912
2913 fn max_intrinsic_width_from(
2914 &self,
2915 index: usize,
2916 frame: &CoordinatorFrame<'_>,
2917 height: f32,
2918 ) -> f32 {
2919 let Some(node) = self.nodes.get(index) else {
2920 return frame
2921 .measure_policy
2922 .max_intrinsic_width(frame.measurables, height);
2923 };
2924 let wrapped = CoordinatorLink {
2925 chain: self,
2926 frame,
2927 index: index + 1,
2928 };
2929 let node_borrow = node.node.borrow();
2930 node_borrow.as_layout_node().map_or_else(
2931 || wrapped.max_intrinsic_width(height),
2932 |layout_node| layout_node.max_intrinsic_width(&wrapped, height, frame.scope.density()),
2933 )
2934 }
2935
2936 fn min_intrinsic_height_from(
2937 &self,
2938 index: usize,
2939 frame: &CoordinatorFrame<'_>,
2940 width: f32,
2941 ) -> f32 {
2942 let Some(node) = self.nodes.get(index) else {
2943 return frame
2944 .measure_policy
2945 .min_intrinsic_height(frame.measurables, width);
2946 };
2947 let wrapped = CoordinatorLink {
2948 chain: self,
2949 frame,
2950 index: index + 1,
2951 };
2952 let node_borrow = node.node.borrow();
2953 node_borrow.as_layout_node().map_or_else(
2954 || wrapped.min_intrinsic_height(width),
2955 |layout_node| layout_node.min_intrinsic_height(&wrapped, width, frame.scope.density()),
2956 )
2957 }
2958
2959 fn max_intrinsic_height_from(
2960 &self,
2961 index: usize,
2962 frame: &CoordinatorFrame<'_>,
2963 width: f32,
2964 ) -> f32 {
2965 let Some(node) = self.nodes.get(index) else {
2966 return frame
2967 .measure_policy
2968 .max_intrinsic_height(frame.measurables, width);
2969 };
2970 let wrapped = CoordinatorLink {
2971 chain: self,
2972 frame,
2973 index: index + 1,
2974 };
2975 let node_borrow = node.node.borrow();
2976 node_borrow.as_layout_node().map_or_else(
2977 || wrapped.max_intrinsic_height(width),
2978 |layout_node| layout_node.max_intrinsic_height(&wrapped, width, frame.scope.density()),
2979 )
2980 }
2981
2982 fn write_geometry(
2986 &self,
2987 geometry: &crate::modifier::CoordinatorGeometry,
2988 node_offset: Point,
2989 ) -> bool {
2990 let content = self.total_content_offset_from(0);
2991 let placed = |inner_offset: Point, size: Size| GeometryRect {
2992 x: content.x - inner_offset.x - node_offset.x,
2993 y: content.y - inner_offset.y - node_offset.y,
2994 width: size.width,
2995 height: size.height,
2996 };
2997 geometry.replace(
2998 self.nodes
2999 .iter()
3000 .map(|node| placed(node.accumulated_offset.get(), node.measured_size.get()))
3001 .chain(std::iter::once(placed(
3002 Point::default(),
3003 self.inner_size.get(),
3004 ))),
3005 )
3006 }
3007
3008 fn total_content_offset_from(&self, index: usize) -> Point {
3009 self.nodes
3010 .get(index)
3011 .map(|node| node.accumulated_offset.get())
3012 .unwrap_or_default()
3013 }
3014
3015 #[cfg(test)]
3016 fn debug_ptrs(&self) -> Vec<usize> {
3017 self.nodes.iter().map(CoordinatorNode::ptr).collect()
3018 }
3019}
3020
3021#[derive(Default)]
3022pub(crate) struct LayoutRuntimeState {
3023 child_ids: Vec<NodeId>,
3024 child_states: Vec<Rc<LayoutChildMeasureState>>,
3025 child_measurables: Vec<Box<dyn Measurable>>,
3026 coordinator_chain: CoordinatorChain,
3027 error: Rc<RefCell<Option<NodeError>>>,
3030}
3031
3032impl LayoutRuntimeState {
3033 fn reconcile_child_measurables(&mut self, child_ids: &[NodeId]) {
3034 if self.child_ids == child_ids {
3035 return;
3036 }
3037
3038 let mut previous_ids = std::mem::take(&mut self.child_ids);
3039 let mut previous_states = std::mem::take(&mut self.child_states);
3040 let mut previous_measurables = std::mem::take(&mut self.child_measurables);
3041
3042 self.child_ids.reserve(child_ids.len());
3043 self.child_states.reserve(child_ids.len());
3044 self.child_measurables.reserve(child_ids.len());
3045
3046 for &child_id in child_ids {
3047 if let Some(position) = previous_ids.iter().position(|&id| id == child_id) {
3048 self.child_ids.push(previous_ids.swap_remove(position));
3049 self.child_states
3050 .push(previous_states.swap_remove(position));
3051 self.child_measurables
3052 .push(previous_measurables.swap_remove(position));
3053 } else {
3054 let state = LayoutChildMeasureState::new(child_id);
3055 self.child_ids.push(child_id);
3056 self.child_states.push(Rc::clone(&state));
3057 self.child_measurables
3058 .push(Box::new(LayoutChildMeasurable::new(state)));
3059 }
3060 }
3061 }
3062
3063 fn child_state(&self, index: usize) -> Rc<LayoutChildMeasureState> {
3064 Rc::clone(&self.child_states[index])
3065 }
3066
3067 fn child_measurables(&self) -> &[Box<dyn Measurable>] {
3068 self.child_measurables.as_slice()
3069 }
3070
3071 fn reconcile_coordinator_chain(&mut self, layout_node_data: &[LayoutModifierNodeData]) {
3072 self.coordinator_chain.reconcile(layout_node_data);
3073 }
3074
3075 fn coordinator_chain(&self) -> &CoordinatorChain {
3076 &self.coordinator_chain
3077 }
3078
3079 fn clear_frame_bindings(&self) {
3080 for child_state in &self.child_states {
3081 child_state.clear_frame_bindings();
3082 }
3083 }
3084
3085 #[cfg(test)]
3086 pub(crate) fn debug_stats(&self) -> LayoutRuntimeDebugStats {
3087 LayoutRuntimeDebugStats {
3088 child_ids: self.child_ids.clone(),
3089 child_state_ptrs: self
3090 .child_states
3091 .iter()
3092 .map(|state| Rc::as_ptr(state) as *const () as usize)
3093 .collect(),
3094 child_measurable_ptrs: self
3095 .child_measurables
3096 .iter()
3097 .map(|measurable| {
3098 measurable.as_ref() as *const dyn Measurable as *const () as usize
3099 })
3100 .collect(),
3101 child_measurable_count: self.child_measurables.len(),
3102 coordinator_node_ptrs: self.coordinator_chain.debug_ptrs(),
3103 coordinator_node_count: self.coordinator_chain.nodes.len(),
3104 }
3105 }
3106}
3107
3108#[cfg(test)]
3109#[derive(Debug, Clone, PartialEq, Eq)]
3110pub(crate) struct LayoutRuntimeDebugStats {
3111 pub(crate) child_ids: Vec<NodeId>,
3112 pub(crate) child_state_ptrs: Vec<usize>,
3113 pub(crate) child_measurable_ptrs: Vec<usize>,
3114 pub(crate) child_measurable_count: usize,
3115 pub(crate) coordinator_node_ptrs: Vec<usize>,
3116 pub(crate) coordinator_node_count: usize,
3117}
3118
3119struct LayoutChildMeasureConfig {
3120 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
3121 node_id: NodeId,
3122 error: Rc<RefCell<Option<NodeError>>>,
3123 runtime_handle: Option<RuntimeHandle>,
3124 cache: LayoutNodeCacheHandles,
3125 cache_epoch: u64,
3126 force_remeasure: bool,
3127 measure_handle: Option<LayoutMeasureHandle>,
3128 layout_state: Option<Rc<RefCell<LayoutState>>>,
3129}
3130
3131struct LayoutChildMeasureState {
3132 applier: RefCell<Option<Rc<ConcreteApplierHost<MemoryApplier>>>>,
3133 node_id: Cell<NodeId>,
3134 measured: RefCell<Option<Rc<MeasuredNode>>>,
3135 last_position: Cell<Option<Point>>,
3136 error: RefCell<Option<Rc<RefCell<Option<NodeError>>>>>,
3137 runtime_handle: RefCell<Option<RuntimeHandle>>,
3138 cache: RefCell<LayoutNodeCacheHandles>,
3139 cache_epoch: Cell<u64>,
3140 force_remeasure: Cell<bool>,
3141 measure_handle: RefCell<Option<LayoutMeasureHandle>>,
3142 layout_state: RefCell<Option<Rc<RefCell<LayoutState>>>>,
3143}
3144
3145impl LayoutChildMeasureState {
3146 fn new(node_id: NodeId) -> Rc<Self> {
3147 Rc::new(Self {
3148 applier: RefCell::new(None),
3149 node_id: Cell::new(node_id),
3150 measured: RefCell::new(None),
3151 last_position: Cell::new(None),
3152 error: RefCell::new(None),
3153 runtime_handle: RefCell::new(None),
3154 cache: RefCell::new(LayoutNodeCacheHandles::default()),
3155 cache_epoch: Cell::new(0),
3156 force_remeasure: Cell::new(true),
3157 measure_handle: RefCell::new(None),
3158 layout_state: RefCell::new(None),
3159 })
3160 }
3161
3162 fn configure(&self, config: LayoutChildMeasureConfig) {
3163 config.cache.activate(config.cache_epoch);
3164 *self.applier.borrow_mut() = Some(config.applier);
3165 self.node_id.set(config.node_id);
3166 self.measured.borrow_mut().take();
3167 self.last_position.set(None);
3168 *self.error.borrow_mut() = Some(config.error);
3169 *self.runtime_handle.borrow_mut() = config.runtime_handle;
3170 *self.cache.borrow_mut() = config.cache;
3171 self.cache_epoch.set(config.cache_epoch);
3172 self.force_remeasure.set(config.force_remeasure);
3173 *self.measure_handle.borrow_mut() = config.measure_handle;
3174 *self.layout_state.borrow_mut() = config.layout_state;
3175 }
3176
3177 fn clear_frame_bindings(&self) {
3178 self.measured.borrow_mut().take();
3179 *self.applier.borrow_mut() = None;
3180 *self.error.borrow_mut() = None;
3181 *self.runtime_handle.borrow_mut() = None;
3182 *self.measure_handle.borrow_mut() = None;
3183 *self.layout_state.borrow_mut() = None;
3184 }
3185
3186 fn node_id(&self) -> NodeId {
3187 self.node_id.get()
3188 }
3189
3190 fn cache(&self) -> LayoutNodeCacheHandles {
3191 self.cache.borrow().clone()
3192 }
3193
3194 fn applier(&self) -> Option<Rc<ConcreteApplierHost<MemoryApplier>>> {
3195 self.applier.borrow().clone()
3196 }
3197
3198 fn layout_state(&self) -> Option<Rc<RefCell<LayoutState>>> {
3199 self.layout_state.borrow().clone()
3200 }
3201
3202 fn take_measured(&self) -> Option<Rc<MeasuredNode>> {
3203 self.measured.borrow_mut().take()
3204 }
3205
3206 fn last_position(&self) -> Option<Point> {
3207 self.last_position.get()
3208 }
3209
3210 fn set_last_position(&self, position: Point) {
3211 self.last_position.set(Some(position));
3212 }
3213
3214 fn place_retained(&self, position: Point) {
3215 self.set_last_position(position);
3216 if let Some(layout_state) = self.layout_state() {
3217 layout_state.borrow_mut().place(position);
3218 return;
3219 }
3220 let Some(applier) = self.applier() else {
3221 return;
3222 };
3223 let Ok(mut applier) = applier.try_borrow_typed() else {
3224 return;
3225 };
3226 let node_id = self.node_id();
3227 if applier
3228 .with_node::<LayoutNode, _>(node_id, |node| {
3229 node.set_position(position);
3230 })
3231 .is_err()
3232 {
3233 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
3234 node.set_position(position);
3235 });
3236 }
3237 }
3238
3239 fn set_measured(&self, measured: Option<Rc<MeasuredNode>>) {
3240 *self.measured.borrow_mut() = measured;
3241 }
3242
3243 fn record_error(&self, err: NodeError) {
3244 let Some(error) = self.error.borrow().clone() else {
3245 return;
3246 };
3247 let mut slot = error.borrow_mut();
3248 if slot.is_none() {
3249 *slot = Some(err);
3250 }
3251 }
3252
3253 fn perform_measure(&self, constraints: Constraints) -> Result<Rc<MeasuredNode>, NodeError> {
3254 let node_id = self.node_id();
3255 if let Some(handle) = self.measure_handle.borrow().clone() {
3256 return handle.measure(node_id, constraints);
3257 }
3258 let applier = self.applier().ok_or(NodeError::MissingContext {
3259 id: node_id,
3260 reason: "layout child applier not configured",
3261 })?;
3262 measure_node_with_host(
3263 applier,
3264 self.runtime_handle.borrow().clone(),
3265 node_id,
3266 constraints,
3267 self.cache_epoch.get(),
3268 )
3269 }
3270
3271 fn intrinsic_measure(&self, constraints: Constraints) -> Option<Rc<MeasuredNode>> {
3272 let cache = self.cache();
3273 cache.activate(self.cache_epoch.get());
3274 if !self.force_remeasure.get()
3275 && let Some(cached) = cache.get_measurement(constraints)
3276 {
3277 return Some(cached);
3278 }
3279
3280 match self.perform_measure(constraints) {
3281 Ok(measured) => {
3282 self.force_remeasure.set(false);
3283 cache.store_measurement(constraints, Rc::clone(&measured));
3284 Some(measured)
3285 }
3286 Err(err) => {
3287 self.record_error(err);
3288 None
3289 }
3290 }
3291 }
3292}
3293
3294struct LayoutChildMeasurable {
3295 state: Rc<LayoutChildMeasureState>,
3296}
3297
3298impl LayoutChildMeasurable {
3299 fn new(state: Rc<LayoutChildMeasureState>) -> Self {
3300 Self { state }
3301 }
3302
3303 fn resolved_parent_data(&self) -> Option<cranpose_ui_layout::ParentData> {
3304 let applier = self.state.applier()?;
3305 let node_id = self.state.node_id();
3306 let Ok(mut applier) = applier.try_borrow_typed() else {
3307 return None;
3308 };
3309
3310 applier
3311 .with_node::<LayoutNode, _>(node_id, |layout_node| {
3312 let props = layout_node.resolved_modifiers().layout_properties();
3313 let weight = props.weight().unwrap_or_default();
3314 cranpose_ui_layout::ParentData {
3315 weight: weight.weight,
3316 fill: weight.fill,
3317 box_alignment: props.box_alignment(),
3318 row_alignment: props.row_alignment(),
3319 column_alignment: props.column_alignment(),
3320 }
3321 })
3322 .ok()
3323 }
3324}
3325
3326impl PlaceTarget for LayoutChildMeasureState {
3327 fn place(&self, x: f32, y: f32) {
3328 let internal_offset = self
3329 .measured
3330 .borrow()
3331 .as_ref()
3332 .map(|measured| measured.offset)
3333 .unwrap_or_default();
3334 self.place_retained(Point {
3335 x: x + internal_offset.x,
3336 y: y + internal_offset.y,
3337 });
3338 }
3339}
3340
3341impl Measurable for LayoutChildMeasurable {
3342 fn measure(&self, constraints: Constraints) -> Placeable {
3343 let state = &self.state;
3344 let cache = state.cache();
3345 cache.activate(state.cache_epoch.get());
3346 let measured_size;
3347 if !state.force_remeasure.get() {
3348 if let Some(cached) = cache.get_measurement(constraints) {
3349 measured_size = cached.size;
3350 state.set_measured(Some(Rc::clone(&cached)));
3351 } else {
3352 match state.perform_measure(constraints) {
3353 Ok(measured) => {
3354 state.force_remeasure.set(false);
3355 measured_size = measured.size;
3356 cache.store_measurement(constraints, Rc::clone(&measured));
3357 state.set_measured(Some(measured));
3358 }
3359 Err(err) => {
3360 state.record_error(err);
3361 state.set_measured(None);
3362 measured_size = Size {
3363 width: 0.0,
3364 height: 0.0,
3365 };
3366 }
3367 }
3368 }
3369 } else {
3370 match state.perform_measure(constraints) {
3371 Ok(measured) => {
3372 state.force_remeasure.set(false);
3373 measured_size = measured.size;
3374 cache.store_measurement(constraints, Rc::clone(&measured));
3375 state.set_measured(Some(measured));
3376 }
3377 Err(err) => {
3378 state.record_error(err);
3379 state.set_measured(None);
3380 measured_size = Size {
3381 width: 0.0,
3382 height: 0.0,
3383 };
3384 }
3385 }
3386 }
3387
3388 if let Some(layout_state) = state.layout_state() {
3389 let mut layout_state = layout_state.borrow_mut();
3390 layout_state.set_size(measured_size);
3391 } else if let Some(applier) = state.applier() {
3392 let Ok(mut applier) = applier.try_borrow_typed() else {
3393 return Placeable::value(
3394 measured_size.width,
3395 measured_size.height,
3396 state.node_id(),
3397 );
3398 };
3399 let _ = applier.with_node::<LayoutNode, _>(state.node_id(), |node| {
3400 node.set_measured_size(measured_size);
3401 });
3402 }
3403
3404 let size_for_parent = state
3405 .measured
3406 .borrow()
3407 .as_ref()
3408 .map_or(measured_size, |measured| measured.size_for_parent());
3409
3410 Placeable::with_place_target(
3411 size_for_parent.width,
3412 size_for_parent.height,
3413 state.node_id(),
3414 Rc::clone(&self.state) as Rc<dyn PlaceTarget>,
3415 )
3416 }
3417
3418 fn min_intrinsic_width(&self, height: f32) -> f32 {
3419 let kind = IntrinsicKind::MinWidth(height);
3420 let cache = self.state.cache();
3421 cache.activate(self.state.cache_epoch.get());
3422 if !self.state.force_remeasure.get()
3423 && let Some(value) = cache.get_intrinsic(&kind)
3424 {
3425 return value;
3426 }
3427 let constraints = Constraints {
3428 min_width: 0.0,
3429 max_width: f32::INFINITY,
3430 min_height: height,
3431 max_height: height,
3432 };
3433 if let Some(node) = self.state.intrinsic_measure(constraints) {
3434 let value = node.size_for_parent().width;
3435 cache.store_intrinsic(kind, value);
3436 value
3437 } else {
3438 0.0
3439 }
3440 }
3441
3442 fn max_intrinsic_width(&self, height: f32) -> f32 {
3443 let kind = IntrinsicKind::MaxWidth(height);
3444 let cache = self.state.cache();
3445 cache.activate(self.state.cache_epoch.get());
3446 if !self.state.force_remeasure.get()
3447 && let Some(value) = cache.get_intrinsic(&kind)
3448 {
3449 return value;
3450 }
3451 let constraints = Constraints {
3452 min_width: 0.0,
3453 max_width: f32::INFINITY,
3454 min_height: 0.0,
3455 max_height: height,
3456 };
3457 if let Some(node) = self.state.intrinsic_measure(constraints) {
3458 let value = node.size_for_parent().width;
3459 cache.store_intrinsic(kind, value);
3460 value
3461 } else {
3462 0.0
3463 }
3464 }
3465
3466 fn min_intrinsic_height(&self, width: f32) -> f32 {
3467 let kind = IntrinsicKind::MinHeight(width);
3468 let cache = self.state.cache();
3469 cache.activate(self.state.cache_epoch.get());
3470 if !self.state.force_remeasure.get()
3471 && let Some(value) = cache.get_intrinsic(&kind)
3472 {
3473 return value;
3474 }
3475 let constraints = Constraints {
3476 min_width: width,
3477 max_width: width,
3478 min_height: 0.0,
3479 max_height: f32::INFINITY,
3480 };
3481 if let Some(node) = self.state.intrinsic_measure(constraints) {
3482 let value = node.size_for_parent().height;
3483 cache.store_intrinsic(kind, value);
3484 value
3485 } else {
3486 0.0
3487 }
3488 }
3489
3490 fn max_intrinsic_height(&self, width: f32) -> f32 {
3491 let kind = IntrinsicKind::MaxHeight(width);
3492 let cache = self.state.cache();
3493 cache.activate(self.state.cache_epoch.get());
3494 if !self.state.force_remeasure.get()
3495 && let Some(value) = cache.get_intrinsic(&kind)
3496 {
3497 return value;
3498 }
3499 let constraints = Constraints {
3500 min_width: 0.0,
3501 max_width: width,
3502 min_height: 0.0,
3503 max_height: f32::INFINITY,
3504 };
3505 if let Some(node) = self.state.intrinsic_measure(constraints) {
3506 let value = node.size_for_parent().height;
3507 cache.store_intrinsic(kind, value);
3508 value
3509 } else {
3510 0.0
3511 }
3512 }
3513
3514 fn flex_parent_data(&self) -> Option<cranpose_ui_layout::FlexParentData> {
3515 let parent_data = self.resolved_parent_data()?;
3516 if !parent_data.has_weight() {
3517 return None;
3518 }
3519 Some(cranpose_ui_layout::FlexParentData::new(
3520 parent_data.weight,
3521 parent_data.fill,
3522 ))
3523 }
3524
3525 fn parent_data(&self) -> cranpose_ui_layout::ParentData {
3526 self.resolved_parent_data().unwrap_or_default()
3527 }
3528}
3529
3530fn measure_node_with_host(
3531 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
3532 runtime_handle: Option<RuntimeHandle>,
3533 node_id: NodeId,
3534 constraints: Constraints,
3535 epoch: u64,
3536) -> Result<Rc<MeasuredNode>, NodeError> {
3537 let runtime_handle = match runtime_handle {
3538 Some(handle) => Some(handle),
3539 None => applier.borrow_typed().runtime_handle(),
3540 };
3541 let mut builder = LayoutBuilder::new_with_epoch(
3542 applier,
3543 epoch,
3544 Rc::new(RefCell::new(SlotTable::default())),
3545 FrameLayoutArena::default(),
3546 );
3547 builder.set_runtime_handle(runtime_handle);
3548 builder.measure_node(node_id, constraints)
3549}
3550
3551#[derive(Clone)]
3552struct RuntimeNodeMetadata {
3553 modifier: Modifier,
3554 resolved_modifiers: ResolvedModifiers,
3555 modifier_slices: Rc<ModifierNodeSlices>,
3556 semantics: Option<Rc<SemanticsConfiguration>>,
3557 role: SemanticsRole,
3558 button_handler: Option<Rc<RefCell<dyn FnMut()>>>,
3559}
3560
3561impl Default for RuntimeNodeMetadata {
3562 fn default() -> Self {
3563 Self {
3564 modifier: Modifier::empty(),
3565 resolved_modifiers: ResolvedModifiers::default(),
3566 modifier_slices: Rc::default(),
3567 semantics: None,
3568 role: SemanticsRole::Unknown,
3569 button_handler: None,
3570 }
3571 }
3572}
3573
3574fn role_from_modifier_slices(modifier_slices: &ModifierNodeSlices) -> SemanticsRole {
3575 modifier_slices
3576 .annotated_text()
3577 .map_or(SemanticsRole::Layout, |text| SemanticsRole::Text {
3578 value: SemanticsText(Rc::clone(text)),
3579 })
3580}
3581
3582fn runtime_metadata_for(
3583 applier: &mut MemoryApplier,
3584 node_id: NodeId,
3585) -> Result<RuntimeNodeMetadata, NodeError> {
3586 if let Ok(meta) = applier.with_node::<LayoutNode, _>(node_id, |layout| {
3587 let modifier = layout.modifier.clone();
3588 let resolved_modifiers = layout.resolved_modifiers();
3589 let modifier_slices = layout.modifier_slices_snapshot();
3590 let role = role_from_modifier_slices(&modifier_slices);
3591
3592 RuntimeNodeMetadata {
3593 modifier,
3594 resolved_modifiers,
3595 modifier_slices,
3596 semantics: layout.semantics_configuration().map(Rc::new),
3597 role,
3598 button_handler: None,
3599 }
3600 }) {
3601 return Ok(meta);
3602 }
3603
3604 if let Ok((modifier, resolved_modifiers, modifier_slices, semantics)) =
3605 applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
3606 (
3607 node.modifier(),
3608 node.resolved_modifiers(),
3609 node.modifier_slices_snapshot(),
3610 node.semantics_configuration().map(Rc::new),
3611 )
3612 })
3613 {
3614 return Ok(RuntimeNodeMetadata {
3615 modifier,
3616 resolved_modifiers,
3617 modifier_slices,
3618 semantics,
3619 role: SemanticsRole::Subcompose,
3620 button_handler: None,
3621 });
3622 }
3623 Ok(RuntimeNodeMetadata::default())
3624}
3625
3626fn clear_semantics_dirty_flags(
3627 applier: &mut MemoryApplier,
3628 node: &MeasuredNode,
3629) -> Result<(), NodeError> {
3630 match applier.with_node::<LayoutNode, _>(node.node_id, |layout| {
3631 layout.clear_needs_semantics();
3632 }) {
3633 Ok(()) => {}
3634 Err(NodeError::Missing { .. }) => {}
3635 Err(NodeError::TypeMismatch { .. }) => {
3636 match applier.with_node::<SubcomposeLayoutNode, _>(node.node_id, |subcompose| {
3637 subcompose.clear_needs_semantics();
3638 }) {
3639 Ok(()) | Err(NodeError::Missing { .. } | NodeError::TypeMismatch { .. }) => {}
3640 Err(err) => return Err(err),
3641 }
3642 }
3643 Err(err) => return Err(err),
3644 }
3645
3646 for child in &node.children {
3647 clear_semantics_dirty_flags(applier, &child.node)?;
3648 }
3649
3650 Ok(())
3651}
3652
3653fn build_semantics_tree_from_live_nodes(
3654 applier: &mut MemoryApplier,
3655 node: &MeasuredNode,
3656) -> Result<SemanticsTree, NodeError> {
3657 Ok(SemanticsTree::new(build_semantics_node_from_live_nodes(
3658 applier, node, None,
3659 )?))
3660}
3661
3662fn semantics_node_from_parts(
3663 node_id: NodeId,
3664 node_generation: u32,
3665 mut role: SemanticsRole,
3666 config: Option<SemanticsConfiguration>,
3667 children: Vec<SemanticsNode>,
3668 bounds: GeometryRect,
3669) -> SemanticsNode {
3670 let mut node = SemanticsNode {
3671 node_id,
3672 bounds,
3673 node_generation,
3674 children,
3675 ..SemanticsNode::default()
3676 };
3677
3678 if let Some(config) = config {
3679 if config.role == Some(SemanticsWidgetRole::Button) {
3680 role = SemanticsRole::Button;
3681 }
3682 if config.is_activatable() {
3683 node.actions.push(SemanticsAction::Click {
3684 handler: SemanticsCallback::new(node_id),
3685 });
3686 }
3687 node.widget_role = config.role;
3688 node.description = config.content_description;
3689 node.state_description = config.state_description;
3690 node.on_click_label = config.on_click_label.or_else(|| {
3691 config
3692 .on_click
3693 .as_ref()
3694 .and_then(|action| (!action.label.is_empty()).then(|| action.label.clone()))
3695 });
3696 node.on_click = config.on_click;
3697 node.on_long_click = config.on_long_click;
3698 node.on_long_click_label = config.on_long_click_label;
3699 node.on_magic_tap = config.on_magic_tap;
3700 node.on_magic_tap_label = config.on_magic_tap_label;
3701 node.input_labels = config.input_labels;
3702 node.language = config.language;
3703 node.selected = config.selected;
3704 node.toggled = config.toggled;
3705 node.enabled = config.enabled;
3706 node.custom_actions = config.custom_actions;
3707 node.canvas_children = config.canvas_children;
3708 node.editable_text = config.is_editable_text;
3709 node.multiline = config.multiline;
3710 node.hidden = config.hidden;
3711 node.is_modal = config.is_modal
3712 && modal_takes_space(Size {
3713 width: bounds.width,
3714 height: bounds.height,
3715 });
3716 node.merge_descendants = config.merge_descendants;
3717 node.selectable_group = config.selectable_group;
3718 node.pane_title = config.pane_title;
3719 node.error = config.error;
3720 node.password = config.password;
3721 node.traversal_index = config.traversal_index;
3722 node.text = config.text;
3723 node.text_selection = config.text_selection;
3724 node.live_region = config.live_region;
3725 node.progress = config.progress;
3726 node.set_progress = config.set_progress;
3727 node.set_text = config.set_text;
3728 node.set_selection = config.set_selection;
3729 node.expand = config.expand;
3730 node.collapse = config.collapse;
3731 node.dismiss = config.dismiss;
3732 node.vertical_scroll = config.vertical_scroll;
3733 node.horizontal_scroll = config.horizontal_scroll;
3734 node.scroll_by = config.scroll_by;
3735 node.scroll_to_index = config.scroll_to_index;
3736 node.collection = config.collection;
3737 }
3738
3739 node.focusable = crate::focus_dispatch::has_focus_target(node_id);
3740 node.focused = node.focusable && crate::focus_dispatch::active_focus_target() == Some(node_id);
3741
3742 node.role = role;
3743 node
3744}
3745
3746fn build_semantics_node_from_live_nodes(
3747 applier: &mut MemoryApplier,
3748 node: &MeasuredNode,
3749 origin: Option<Point>,
3750) -> Result<SemanticsNode, NodeError> {
3751 let (role, config, (bounds, content)) =
3752 match applier.with_node::<LayoutNode, _>(node.node_id, |layout| {
3753 let role = role_from_modifier_slices(&layout.modifier_slices_snapshot());
3754 let config = layout.semantics_configuration();
3755 layout.clear_needs_semantics();
3756 (
3757 role,
3758 config,
3759 semantics_placement(&layout.layout_state(), origin),
3760 )
3761 }) {
3762 Ok(data) => data,
3763 Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => {
3764 match applier.with_node::<SubcomposeLayoutNode, _>(node.node_id, |subcompose| {
3765 subcompose.clear_needs_semantics();
3766 (
3767 SemanticsRole::Subcompose,
3768 subcompose.semantics_configuration(),
3769 semantics_placement(&subcompose.layout_state(), origin),
3770 )
3771 }) {
3772 Ok(data) => data,
3773 Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => {
3774 let top_left = origin.unwrap_or_default();
3775 (
3776 SemanticsRole::Unknown,
3777 None,
3778 (
3779 GeometryRect::from_origin_size(top_left, node.size),
3780 top_left,
3781 ),
3782 )
3783 }
3784 Err(err) => return Err(err),
3785 }
3786 }
3787 Err(err) => return Err(err),
3788 };
3789
3790 let mut children = Vec::with_capacity(node.children.len());
3791 for child in &node.children {
3792 children.push(build_semantics_node_from_live_nodes(
3793 applier,
3794 &child.node,
3795 Some(content),
3796 )?);
3797 }
3798
3799 Ok(semantics_node_from_parts(
3800 node.node_id,
3801 applier.node_generation(node.node_id),
3802 role,
3803 config,
3804 children,
3805 bounds,
3806 ))
3807}
3808
3809fn record_semantics_allocation_stats(node: &SemanticsNode, stats: &mut LayoutAllocationDebugStats) {
3810 stats.semantics_node_count += 1;
3811 stats.semantics_action_count += node.actions.len();
3812 stats.semantics_action_capacity += node.actions.capacity();
3813 stats.semantics_child_count += node.children.len();
3814 stats.semantics_child_capacity += node.children.capacity();
3815 stats.semantics_heap_bytes += node.actions.capacity() * size_of::<SemanticsAction>();
3816 stats.semantics_heap_bytes += node.children.capacity() * size_of::<SemanticsNode>();
3817
3818 if let Some(description) = &node.description {
3819 stats.semantics_description_count += 1;
3820 stats.semantics_description_bytes += description.capacity();
3821 stats.semantics_heap_bytes += description.capacity();
3822 }
3823
3824 for child in &node.children {
3825 record_semantics_allocation_stats(child, stats);
3826 }
3827}
3828
3829fn record_layout_box_allocation_stats(
3830 layout_box: &LayoutBox,
3831 stats: &mut LayoutAllocationDebugStats,
3832) {
3833 stats.layout_box_count += 1;
3834 stats.layout_box_child_count += layout_box.children.len();
3835 stats.layout_box_child_capacity += layout_box.children.capacity();
3836 stats.layout_box_heap_bytes += layout_box.children.capacity() * size_of::<LayoutBox>();
3837 stats.add_modifier_slice(layout_box.node_data.modifier_slices().debug_stats());
3838
3839 for child in &layout_box.children {
3840 record_layout_box_allocation_stats(child, stats);
3841 }
3842}
3843
3844fn build_layout_tree(
3845 applier: &mut MemoryApplier,
3846 node: &MeasuredNode,
3847) -> Result<LayoutTree, NodeError> {
3848 fn place(
3849 applier: &mut MemoryApplier,
3850 node: &MeasuredNode,
3851 origin: Point,
3852 parent_layer_translation: Point,
3853 ) -> Result<LayoutBox, NodeError> {
3854 let top_left = Point {
3855 x: origin.x + node.offset.x,
3856 y: origin.y + node.offset.y,
3857 };
3858 let rect = GeometryRect {
3859 x: top_left.x,
3860 y: top_left.y,
3861 width: node.size.width,
3862 height: node.size.height,
3863 };
3864 let (data, layer_translation) = snapshot_node_data(
3865 applier,
3866 node.node_id,
3867 top_left,
3868 node.size,
3869 parent_layer_translation,
3870 )?;
3871 let mut children = Vec::with_capacity(node.children.len());
3872 for child in &node.children {
3873 if crate::modifier::is_window_root(applier, child.node.node_id) {
3874 continue;
3875 }
3876 let child_origin = Point {
3877 x: top_left.x + child.offset.x,
3878 y: top_left.y + child.offset.y,
3879 };
3880 children.push(place(
3881 applier,
3882 &child.node,
3883 child_origin,
3884 layer_translation,
3885 )?);
3886 }
3887 Ok(LayoutBox {
3888 node_generation: applier.node_generation(node.node_id),
3889 ..LayoutBox::new(node.node_id, rect, node.content_offset, data, children)
3890 })
3891 }
3892
3893 Ok(LayoutTree::new(place(
3894 applier,
3895 node,
3896 Point { x: 0.0, y: 0.0 },
3897 Point { x: 0.0, y: 0.0 },
3898 )?))
3899}
3900
3901fn semantics_role_from_layout_box(layout_box: &LayoutBox) -> SemanticsRole {
3902 match &layout_box.node_data.kind {
3903 LayoutNodeKind::Subcompose => SemanticsRole::Subcompose,
3904 LayoutNodeKind::Spacer => SemanticsRole::Spacer,
3905 LayoutNodeKind::Unknown => SemanticsRole::Unknown,
3906 LayoutNodeKind::Button { .. } => SemanticsRole::Button,
3907 LayoutNodeKind::Layout => role_from_modifier_slices(layout_box.node_data.modifier_slices()),
3908 }
3909}
3910
3911fn build_semantics_node_from_layout_box(layout_box: &LayoutBox) -> SemanticsNode {
3912 let children = layout_box
3913 .children
3914 .iter()
3915 .map(build_semantics_node_from_layout_box)
3916 .collect();
3917
3918 semantics_node_from_parts(
3919 layout_box.node_id,
3920 layout_box.node_generation,
3921 semantics_role_from_layout_box(layout_box),
3922 layout_box.node_data.semantics().cloned(),
3923 children,
3924 layout_box.rect,
3925 )
3926}
3927
3928fn layout_kind_from_metadata(_node_id: NodeId, info: &RuntimeNodeMetadata) -> LayoutNodeKind {
3929 match &info.role {
3930 SemanticsRole::Layout => LayoutNodeKind::Layout,
3931 SemanticsRole::Subcompose => LayoutNodeKind::Subcompose,
3932 SemanticsRole::Text { .. } => LayoutNodeKind::Layout,
3933 SemanticsRole::Spacer => LayoutNodeKind::Spacer,
3934 SemanticsRole::Button => {
3935 let handler = info
3936 .button_handler
3937 .as_ref()
3938 .cloned()
3939 .unwrap_or_else(|| Rc::new(RefCell::new(|| {})));
3940 LayoutNodeKind::Button { on_click: handler }
3941 }
3942 SemanticsRole::Unknown => LayoutNodeKind::Unknown,
3943 }
3944}
3945
3946fn subtract_padding(constraints: Constraints, padding: EdgeInsets) -> Constraints {
3947 let horizontal = padding.horizontal_sum();
3948 let vertical = padding.vertical_sum();
3949 let min_width = (constraints.min_width - horizontal).max(0.0);
3950 let mut max_width = constraints.max_width;
3951 if max_width.is_finite() {
3952 max_width = (max_width - horizontal).max(0.0);
3953 }
3954 let min_height = (constraints.min_height - vertical).max(0.0);
3955 let mut max_height = constraints.max_height;
3956 if max_height.is_finite() {
3957 max_height = (max_height - vertical).max(0.0);
3958 }
3959 normalize_constraints(Constraints {
3960 min_width,
3961 max_width,
3962 min_height,
3963 max_height,
3964 })
3965}
3966
3967fn resolve_dimension(
3968 base: f32,
3969 explicit: DimensionConstraint,
3970 min_override: Option<f32>,
3971 max_override: Option<f32>,
3972 min_limit: f32,
3973 max_limit: f32,
3974) -> f32 {
3975 let mut min_bound = min_limit;
3976 if let Some(min_value) = min_override {
3977 min_bound = min_bound.max(min_value);
3978 }
3979
3980 let mut max_bound = if max_limit.is_finite() {
3981 max_limit
3982 } else {
3983 max_override.unwrap_or(max_limit)
3984 };
3985 if let Some(max_value) = max_override {
3986 if max_bound.is_finite() {
3987 max_bound = max_bound.min(max_value);
3988 } else {
3989 max_bound = max_value;
3990 }
3991 }
3992 if max_bound < min_bound {
3993 max_bound = min_bound;
3994 }
3995
3996 let mut size = match explicit {
3997 DimensionConstraint::Points(points) => points,
3998 DimensionConstraint::Fraction(fraction) => {
3999 if max_limit.is_finite() {
4000 max_limit * fraction.clamp(0.0, 1.0)
4001 } else {
4002 base
4003 }
4004 }
4005 DimensionConstraint::Unspecified => base,
4006 DimensionConstraint::Intrinsic(_) => base,
4007 };
4008
4009 size = clamp_dimension(size, min_bound, max_bound);
4010 size = clamp_dimension(size, min_limit, max_limit);
4011 size.max(0.0)
4012}
4013
4014fn clamp_dimension(value: f32, min: f32, max: f32) -> f32 {
4015 let mut result = value.max(min);
4016 if max.is_finite() {
4017 result = result.min(max);
4018 }
4019 result
4020}
4021
4022fn normalize_constraints(mut constraints: Constraints) -> Constraints {
4023 if constraints.max_width < constraints.min_width {
4024 constraints.max_width = constraints.min_width;
4025 }
4026 if constraints.max_height < constraints.min_height {
4027 constraints.max_height = constraints.min_height;
4028 }
4029 constraints
4030}
4031
4032#[cfg(test)]
4033#[path = "tests/layout_tests.rs"]
4034mod tests;
4035
4036#[cfg(test)]
4037#[path = "tests/semantics_update_tests.rs"]
4038mod semantics_update_tests;
4039
4040#[cfg(test)]
4041#[path = "tests/coordinator_geometry_tests.rs"]
4042mod coordinator_geometry_tests;