Skip to main content

cranpose_ui/layout/
mod.rs

1mod bottom_up;
2/// Re-exports of the alignment, arrangement and measurable types that layout policies use.
3pub mod core;
4pub(crate) mod flex_box;
5pub(crate) mod grid;
6/// Measure policies behind the built-in layout widgets such as `Box`, `Row` and `Column`.
7pub mod policies;
8mod reveal;
9mod semantics_details;
10mod semantics_labels;
11mod semantics_update;
12
13use std::{
14    cell::{Cell, RefCell},
15    fmt,
16    mem::size_of,
17    rc::Rc,
18    sync::OnceLock,
19};
20
21use cranpose_core::{
22    Applier, ApplierHost, ConcreteApplierHost, MemoryApplier, Node, NodeError, NodeId,
23    RuntimeHandle,
24};
25use cranpose_foundation::{
26    InvalidationKind, ModifierNodeContext, NodeCapabilities, SemanticsConfiguration,
27    SemanticsCustomAction, SemanticsWidgetRole, lazy::LazyItemRoots,
28};
29use cranpose_ui_graphics::{ProjectiveTransform, layer_transform::layer_transform_to_window};
30use cranpose_ui_layout::{AlignmentLines, Constraints, MeasurePolicy, PlaceTarget, Placement};
31use web_time::Instant;
32
33#[cfg(test)]
34use self::core::{HorizontalAlignment, VerticalAlignment};
35use self::{
36    core::{Measurable, Placeable},
37    semantics_update::semantics_placement,
38};
39pub use self::{
40    reveal::can_skip_scroll_reveal_from_applier,
41    semantics_details::SemanticsDetails,
42    semantics_update::{build_semantics_tree_from_applier, update_semantics_tree_from_applier},
43};
44use crate::{
45    modifier::{
46        DimensionConstraint, EdgeInsets, Modifier, ModifierNodeSlices,
47        ModifierNodeSlicesDebugStats, Point, Rect as GeometryRect, ResolvedModifiers, Size,
48    },
49    render_state::AppContext,
50    subcompose_layout::{MeasureCallbacks, SubcomposeLayoutNode},
51    widgets::nodes::{IntrinsicKind, LayoutNode, LayoutNodeCacheHandles, LayoutState},
52};
53
54#[derive(Default)]
55pub(crate) struct LayoutNodeContext {
56    invalidations: Vec<InvalidationKind>,
57    update_requested: bool,
58    density: f32,
59}
60
61impl LayoutNodeContext {
62    pub(crate) fn new(density: f32) -> Self {
63        Self {
64            density,
65            ..Self::default()
66        }
67    }
68
69    pub(crate) fn take_invalidations(&mut self) -> Vec<InvalidationKind> {
70        std::mem::take(&mut self.invalidations)
71    }
72}
73
74impl ModifierNodeContext for LayoutNodeContext {
75    fn invalidate(&mut self, kind: InvalidationKind) {
76        if !self.invalidations.contains(&kind) {
77            self.invalidations.push(kind);
78        }
79    }
80
81    fn request_update(&mut self) {
82        self.update_requested = true;
83    }
84
85    fn density(&self) -> f32 {
86        self.density
87    }
88}
89
90#[doc(hidden)]
91pub fn invalidate_all_layout_caches() {
92    crate::render_state::invalidate_layout_cache_epoch();
93}
94
95fn layout_measure_telemetry_threshold_ms() -> Option<f64> {
96    static THRESHOLD_MS: OnceLock<Option<f64>> = OnceLock::new();
97    *THRESHOLD_MS.get_or_init(|| {
98        std::env::var("CRANPOSE_LAYOUT_MEASURE_TELEMETRY_MS")
99            .ok()
100            .and_then(|value| value.parse::<f64>().ok())
101            .filter(|value| value.is_finite() && *value >= 0.0)
102            .or_else(|| {
103                std::env::var_os("CRANPOSE_LAYOUT_MEASURE_TELEMETRY")
104                    .is_some()
105                    .then_some(4.0)
106            })
107    })
108}
109
110/// The stages of a layout pass that its telemetry times: start, repasses,
111/// applier guard, builder, measure, root placement, layout and semantics
112/// trees, builder drop and guard drop.
113type LayoutStages = cranpose_core::StageTimes<9>;
114
115fn log_layout_measure_telemetry(root: NodeId, stages: &LayoutStages) {
116    let Some(threshold_ms) = layout_measure_telemetry_threshold_ms() else {
117        return;
118    };
119    let Some(
120        [
121            start,
122            after_repasses,
123            after_guard,
124            after_builder,
125            after_measure,
126            after_root_place,
127            after_aux,
128            after_builder_drop,
129            after_guard_drop,
130        ],
131    ) = stages.times()
132    else {
133        return;
134    };
135    let ms = cranpose_core::stage_ms;
136    let total_ms = ms(start, after_guard_drop);
137    if total_ms < threshold_ms {
138        return;
139    }
140    log::warn!(
141        "[layout-measure-telemetry] root={root} total_ms={total_ms:.2} repass_ms={:.2} guard_ms={:.2} builder_ms={:.2} measure_ms={:.2} root_place_ms={:.2} aux_ms={:.2} builder_drop_ms={:.2} guard_drop_ms={:.2}",
142        ms(start, after_repasses),
143        ms(after_repasses, after_guard),
144        ms(after_guard, after_builder),
145        ms(after_builder, after_measure),
146        ms(after_measure, after_root_place),
147        ms(after_root_place, after_aux),
148        ms(after_aux, after_builder_drop),
149        ms(after_builder_drop, after_guard_drop),
150    );
151}
152
153fn log_node_measure_telemetry(
154    kind: &'static str,
155    node_id: NodeId,
156    constraints: Constraints,
157    measured: &MeasuredNode,
158    (threshold_ms, start): (f64, Instant),
159) {
160    let size = measured.size;
161    let children = measured.children.len();
162    let total_ms = start.elapsed().as_secs_f64() * 1000.0;
163    if total_ms < threshold_ms {
164        return;
165    }
166
167    log::warn!(
168        "[layout-node-telemetry] kind={kind} node={} total_ms={total_ms:.2} constraints=({:.1},{:.1},{:.1},{:.1}) size=({:.1},{:.1}) children={children}",
169        node_id,
170        constraints.min_width,
171        constraints.max_width,
172        constraints.min_height,
173        constraints.max_height,
174        size.width,
175        size.height,
176    );
177}
178
179/// The host a layout pass lends its applier to. Between passes it holds an
180/// empty applier and the app context keeps it, so a pass builds neither.
181pub(crate) struct LayoutHost {
182    host: Rc<ConcreteApplierHost<MemoryApplier>>,
183}
184
185impl Default for LayoutHost {
186    fn default() -> Self {
187        Self {
188            host: Rc::new(ConcreteApplierHost::new(MemoryApplier::new())),
189        }
190    }
191}
192
193/// Lends `target` to a [`LayoutHost`] of `context` for one pass and gives it
194/// back when dropped, also after a panic.
195struct ApplierSlotGuard<'a> {
196    target: &'a mut MemoryApplier,
197    lent: LayoutHost,
198    context: &'a AppContext,
199}
200
201impl<'a> ApplierSlotGuard<'a> {
202    fn new(target: &'a mut MemoryApplier, context: &'a AppContext) -> Self {
203        let lent = context.take_layout_host();
204        std::mem::swap(target, &mut *lent.host.borrow_typed());
205        Self {
206            target,
207            lent,
208            context,
209        }
210    }
211
212    fn host(&self) -> &Rc<ConcreteApplierHost<MemoryApplier>> {
213        &self.lent.host
214    }
215}
216
217impl Drop for ApplierSlotGuard<'_> {
218    fn drop(&mut self) {
219        let host = &self.lent.host;
220        std::mem::swap(self.target, &mut *host.borrow_typed());
221        // A host still shared past the pass stays with whoever holds it.
222        if Rc::strong_count(host) == 1 {
223            self.context.replace_layout_host(LayoutHost {
224                host: Rc::clone(host),
225            });
226        }
227    }
228}
229
230#[derive(Clone, Copy, PartialEq)]
231struct ModifierChainInputs {
232    density: crate::density::Density,
233    window_root: bool,
234    offset: Point,
235    uses_chain: bool,
236}
237
238struct ModifierChainMeasurement {
239    size: Size,
240    alignment_lines: AlignmentLines,
241    content_offset: Point,
242    offset: Point,
243    window_root: bool,
244    uses_chain: bool,
245    /// The incoming constraints this measurement holds for besides its own.
246    hold: Option<cranpose_ui_layout::ConstraintsHold>,
247    /// Whether no child's size entered it: see
248    /// [`MeasurePolicy::ignores_child_sizes`].
249    ignores_child_sizes: bool,
250}
251
252struct ScratchVecPool<T> {
253    available: Vec<Vec<T>>,
254}
255
256impl<T> ScratchVecPool<T> {
257    fn acquire(&mut self) -> Vec<T> {
258        self.available.pop().unwrap_or_default()
259    }
260
261    fn release(&mut self, mut values: Vec<T>) {
262        values.clear();
263        self.available.push(values);
264    }
265
266    #[cfg(test)]
267    fn available_count(&self) -> usize {
268        self.available.len()
269    }
270}
271
272impl<T> Default for ScratchVecPool<T> {
273    fn default() -> Self {
274        Self {
275            available: Vec::new(),
276        }
277    }
278}
279
280#[derive(Default)]
281pub(crate) struct FrameLayoutArena {
282    tmp_child_ids: ScratchVecPool<NodeId>,
283    tmp_placements: ScratchVecPool<Placement>,
284    /// The marks a pass that starts from the dirty nodes cleared.
285    cleared_marks: Vec<(NodeId, crate::widgets::nodes::LayoutDirt)>,
286}
287
288#[cfg(test)]
289impl FrameLayoutArena {
290    pub(crate) fn available_placement_scratch_count(&self) -> usize {
291        self.tmp_placements.available_count()
292    }
293
294    pub(crate) fn seed_placement_scratch_for_test(&mut self) {
295        self.tmp_placements.release(Vec::with_capacity(1));
296    }
297}
298
299/// Discrete event callback reference produced during semantics extraction.
300#[derive(Clone, Debug, PartialEq, Eq)]
301pub struct SemanticsCallback {
302    node_id: NodeId,
303}
304
305impl SemanticsCallback {
306    /// Creates a callback that targets the node with `node_id`.
307    pub fn new(node_id: NodeId) -> Self {
308        Self { node_id }
309    }
310
311    /// Returns the id of the node whose action this callback triggers.
312    pub fn node_id(&self) -> NodeId {
313        self.node_id
314    }
315}
316
317/// Semantics action exposed to the input system.
318#[derive(Clone, Debug, PartialEq, Eq)]
319pub enum SemanticsAction {
320    /// Activates the node, as a tap or a keyboard or assistive technology click does.
321    Click {
322        /// Callback that identifies the node to activate.
323        handler: SemanticsCallback,
324    },
325}
326
327/// A text node's text in the semantics tree, shared with the node's modifier
328/// slices rather than copied out of them.
329#[derive(Clone, Debug)]
330pub struct SemanticsText(Rc<crate::text::AnnotatedString>);
331
332impl SemanticsText {
333    /// The text the node shows.
334    pub fn as_str(&self) -> &str {
335        &self.0.text
336    }
337}
338
339impl PartialEq for SemanticsText {
340    fn eq(&self, other: &Self) -> bool {
341        self.as_str() == other.as_str()
342    }
343}
344
345impl Eq for SemanticsText {}
346
347impl From<&str> for SemanticsText {
348    fn from(text: &str) -> Self {
349        Self(Rc::new(crate::text::AnnotatedString::from(text)))
350    }
351}
352
353/// Semantic role describing how a node should participate in accessibility and hit testing.
354/// Roles are now derived from SemanticsConfiguration rather than widget types.
355#[derive(Clone, Debug, PartialEq, Eq)]
356pub enum SemanticsRole {
357    /// Generic container or layout node
358    Layout,
359    /// Subcomposition boundary
360    Subcompose,
361    /// Text content derived from the text node semantics payload.
362    Text {
363        /// The text the node shows.
364        value: SemanticsText,
365    },
366    /// Spacer (non-interactive)
367    Spacer,
368    /// Button (derived from the semantics `role`)
369    Button,
370    /// Unknown or unspecified role
371    Unknown,
372}
373
374/// A single node within the semantics tree.
375///
376/// Not `Eq`: a node now carries drawn-control bounds, which are floats. The
377/// tree is compared for "did anything a screen reader can see change", and
378/// that comparison is `PartialEq` everywhere else on the accessibility path
379/// (`AccessibilityRect`, `AccessibilityElement`) for the same reason.
380#[derive(Clone, Debug, PartialEq)]
381pub struct SemanticsNode {
382    /// Id of the runtime node this semantics node describes.
383    pub node_id: NodeId,
384    /// Where the node lies in the root's coordinates: its layout rect,
385    /// before graphics-layer transforms, as [`LayoutBox::rect`] holds it.
386    pub bounds: GeometryRect,
387    /// Where layout put the node inside its parent's content, from which a
388    /// tree update moves a node that did not change along with its parent.
389    pub placement: SemanticsPlacement,
390    /// Incarnation of the runtime node, incremented when its storage is recycled.
391    pub node_generation: u32,
392    /// Where this node sits in the tree (layout, text, subcomposition …).
393    pub role: SemanticsRole,
394    /// What kind of control this node is, as a screen reader announces it —
395    /// Compose's `Role`. Separate from [`SemanticsNode::role`] because a
396    /// clickable `Row` is structurally a layout node and semantically a button.
397    pub widget_role: Option<SemanticsWidgetRole>,
398    /// Actions that the input system and assistive technology can invoke on this node.
399    pub actions: Vec<SemanticsAction>,
400    /// Child semantics nodes, in layout order.
401    pub children: Vec<SemanticsNode>,
402    /// Content description that a screen reader announces for the node, if one was set.
403    pub description: Option<String>,
404    /// Direct activation callback for keyboard and assistive technology.
405    pub on_click: Option<SemanticsCustomAction>,
406    /// Selection state, or `None` if the node is not selectable.
407    pub selected: Option<bool>,
408    /// Checked state, or `None` if the node is not a toggleable control.
409    pub toggled: Option<cranpose_foundation::ToggleableState>,
410    /// Whether the node accepts user interaction. `true` unless the node was disabled.
411    pub enabled: bool,
412    /// Whether a screen reader skips this node and everything under it.
413    pub hidden: bool,
414    /// Whether a screen reader takes this node and the text under it as one
415    /// stop.
416    pub merge_descendants: bool,
417    /// Where a screen reader visits this node among the ones beside it.
418    pub traversal_index: f32,
419    /// The text an editable field holds.
420    pub text: Option<String>,
421    /// Whether this node registered a focus target, so focus can land on it.
422    /// Compose's `SemanticsProperties.Focused` companion.
423    pub focusable: bool,
424    /// Whether focus sits on this node right now.
425    pub focused: bool,
426    /// The properties few nodes set, held only when the node sets one: read
427    /// them through [`SemanticsNode::details`] and write them through
428    /// [`SemanticsNode::set_details`].
429    pub details: Option<Box<SemanticsDetails>>,
430}
431
432impl Default for SemanticsNode {
433    fn default() -> Self {
434        Self {
435            node_id: 0,
436            bounds: GeometryRect::EMPTY,
437            placement: SemanticsPlacement::default(),
438            node_generation: 0,
439            role: SemanticsRole::Unknown,
440            widget_role: None,
441            actions: Vec::new(),
442            children: Vec::new(),
443            description: None,
444            on_click: None,
445            selected: None,
446            toggled: None,
447            enabled: true,
448            hidden: false,
449            merge_descendants: false,
450            traversal_index: 0.0,
451            text: None,
452            focusable: false,
453            focused: false,
454            details: None,
455        }
456    }
457}
458
459/// Where layout put a semantics node: its offset inside its parent's
460/// content and where its own content starts inside it.
461#[derive(Clone, Copy, Debug, Default, PartialEq)]
462pub struct SemanticsPlacement {
463    position: Point,
464    content_offset: Point,
465}
466
467impl SemanticsPlacement {
468    fn of(state: &LayoutState) -> Self {
469        Self {
470            position: state.position(),
471            content_offset: state.content_offset(),
472        }
473    }
474
475    fn place(self, origin: Point) -> (Point, Point) {
476        let top_left = Point {
477            x: origin.x + self.position.x,
478            y: origin.y + self.position.y,
479        };
480        let content = Point {
481            x: top_left.x + self.content_offset.x,
482            y: top_left.y + self.content_offset.y,
483        };
484        (top_left, content)
485    }
486}
487
488/// Rooted semantics tree extracted after layout.
489///
490/// Two trees are equal when they hold the same nodes; what a tree keeps to
491/// bring itself up to date is not compared.
492#[derive(Clone, Debug)]
493pub struct SemanticsTree {
494    full: SemanticsNode,
495    modal: Option<Vec<usize>>,
496    tracking: semantics_update::SemanticsTracking,
497}
498
499impl PartialEq for SemanticsTree {
500    fn eq(&self, other: &Self) -> bool {
501        self.full == other.full && self.modal == other.modal
502    }
503}
504
505impl SemanticsTree {
506    fn new(full: SemanticsNode) -> Self {
507        let modal = top_modal_path(&full);
508        Self {
509            full,
510            modal,
511            tracking: semantics_update::SemanticsTracking::default(),
512        }
513    }
514
515    /// Returns the top visible modal subtree, or the full root when no modal is open.
516    pub fn root(&self) -> &SemanticsNode {
517        self.modal.as_deref().map_or(&self.full, |path| {
518            path.iter()
519                .try_fold(&self.full, |node, &index| node.children.get(index))
520                .unwrap_or(&self.full)
521        })
522    }
523}
524
525/// Whether a modal of `size` takes space; a zero-sized modal hides nothing.
526fn modal_takes_space(size: Size) -> bool {
527    size.width > 0.0 && size.height > 0.0 && size.width.is_finite() && size.height.is_finite()
528}
529
530/// The path to the modal drawn on top: the last visible modal in document
531/// order, a modal inside another preferred to it.
532fn top_modal_path(root: &SemanticsNode) -> Option<Vec<usize>> {
533    fn search(node: &SemanticsNode, path: &mut Vec<usize>) -> bool {
534        if node.hidden {
535            return false;
536        }
537        for (index, child) in node.children.iter().enumerate().rev() {
538            path.push(index);
539            if search(child, path) {
540                return true;
541            }
542            path.pop();
543        }
544        node.details().is_modal
545    }
546    let mut path = Vec::new();
547    search(root, &mut path).then_some(path)
548}
549
550/// Counts and heap sizes of the layout and semantics data that one measure pass retains, for memory
551/// diagnostics.
552#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
553pub struct LayoutAllocationDebugStats {
554    /// Number of `LayoutBox` nodes in the tree.
555    pub layout_box_count: usize,
556    /// Total number of child entries across all layout boxes.
557    pub layout_box_child_count: usize,
558    /// Total allocated capacity of the child vectors across all layout boxes.
559    pub layout_box_child_capacity: usize,
560    /// Heap bytes allocated for the child vectors of all layout boxes.
561    pub layout_box_heap_bytes: usize,
562    /// Number of modifier slice snapshots, one per layout box.
563    pub modifier_slice_count: usize,
564    /// Heap bytes held by all modifier slice snapshots.
565    pub modifier_slice_heap_bytes: usize,
566    /// Number of draw commands collected from modifier nodes.
567    pub modifier_draw_command_count: usize,
568    /// Allocated capacity of the draw command lists.
569    pub modifier_draw_command_capacity: usize,
570    /// Number of pointer input handlers collected from modifier nodes.
571    pub modifier_pointer_input_count: usize,
572    /// Allocated capacity of the pointer input handler lists.
573    pub modifier_pointer_input_capacity: usize,
574    /// Number of layout boxes that carry text content.
575    pub modifier_text_content_count: usize,
576    /// Number of layout boxes that carry a text style.
577    pub modifier_text_style_count: usize,
578    /// Number of layout boxes that carry text layout options.
579    pub modifier_text_layout_options_count: usize,
580    /// Number of layout boxes that carry a prepared text layout.
581    pub modifier_prepared_text_layout_count: usize,
582    /// Number of layout boxes that carry a graphics layer.
583    pub modifier_graphics_layer_count: usize,
584    /// Number of layout boxes that carry a graphics layer resolver.
585    pub modifier_graphics_layer_resolver_count: usize,
586    /// Number of nodes in the semantics tree.
587    pub semantics_node_count: usize,
588    /// Total number of actions across all semantics nodes.
589    pub semantics_action_count: usize,
590    /// Total allocated capacity of the action vectors across all semantics nodes.
591    pub semantics_action_capacity: usize,
592    /// Total number of child entries across all semantics nodes.
593    pub semantics_child_count: usize,
594    /// Total allocated capacity of the child vectors across all semantics nodes.
595    pub semantics_child_capacity: usize,
596    /// Number of semantics nodes that have a content description.
597    pub semantics_description_count: usize,
598    /// Allocated bytes of all content description strings.
599    pub semantics_description_bytes: usize,
600    /// Heap bytes held by the semantics tree: actions, children, details and descriptions.
601    pub semantics_heap_bytes: usize,
602}
603
604impl LayoutAllocationDebugStats {
605    fn add_modifier_slice(&mut self, stats: ModifierNodeSlicesDebugStats) {
606        self.modifier_slice_count += 1;
607        self.modifier_slice_heap_bytes += stats.heap_bytes;
608        self.modifier_draw_command_count += stats.draw_command_count;
609        self.modifier_draw_command_capacity += stats.draw_command_capacity;
610        self.modifier_pointer_input_count += stats.pointer_input_count;
611        self.modifier_pointer_input_capacity += stats.pointer_input_capacity;
612        self.modifier_text_content_count += usize::from(stats.has_text_content);
613        self.modifier_text_style_count += usize::from(stats.has_text_style);
614        self.modifier_text_layout_options_count += usize::from(stats.has_text_layout_options);
615        self.modifier_prepared_text_layout_count += usize::from(stats.has_prepared_text_layout);
616        self.modifier_graphics_layer_count += usize::from(stats.has_graphics_layer);
617        self.modifier_graphics_layer_resolver_count +=
618            usize::from(stats.has_graphics_layer_resolver);
619    }
620}
621
622/// Result of running layout for a Compose tree.
623#[derive(Debug, Clone)]
624pub struct LayoutTree {
625    root: LayoutBox,
626}
627
628impl LayoutTree {
629    /// Wraps `root` as a layout tree.
630    pub fn new(root: LayoutBox) -> Self {
631        Self { root }
632    }
633
634    /// Returns the root layout box.
635    pub fn root(&self) -> &LayoutBox {
636        &self.root
637    }
638
639    /// Returns the root layout box for in-place changes.
640    pub fn root_mut(&mut self) -> &mut LayoutBox {
641        &mut self.root
642    }
643
644    /// Consumes the tree and returns its root layout box.
645    pub fn into_root(self) -> LayoutBox {
646        self.root
647    }
648
649    /// Counts the allocations that the layout boxes of this tree retain.
650    pub fn debug_allocation_stats(&self) -> LayoutAllocationDebugStats {
651        let mut stats = LayoutAllocationDebugStats::default();
652        record_layout_box_allocation_stats(&self.root, &mut stats);
653        stats
654    }
655}
656
657/// Layout information for a single node.
658#[derive(Debug, Clone)]
659pub struct LayoutBox {
660    /// Id of the runtime node this box describes.
661    pub node_id: NodeId,
662    /// Incarnation of the runtime node captured with these layout bounds.
663    pub node_generation: u32,
664    /// Position and size of the node in root coordinates, in logical pixels, before graphics-layer
665    /// transforms.
666    pub rect: GeometryRect,
667    /// Content offset for scroll/inner transforms (applies to children, NOT this node's position)
668    pub content_offset: Point,
669    /// Modifier, semantics and kind data captured with the node.
670    pub node_data: LayoutNodeData,
671    /// Layout boxes of the node's placed children.
672    pub children: Vec<LayoutBox>,
673}
674
675impl LayoutBox {
676    /// Creates a layout box with node generation zero.
677    pub fn new(
678        node_id: NodeId,
679        rect: GeometryRect,
680        content_offset: Point,
681        node_data: LayoutNodeData,
682        children: Vec<LayoutBox>,
683    ) -> Self {
684        Self {
685            node_id,
686            node_generation: 0,
687            rect,
688            content_offset,
689            node_data,
690            children,
691        }
692    }
693}
694
695/// Snapshot of the data required to render a layout node.
696#[derive(Debug, Clone)]
697pub struct LayoutNodeData {
698    /// Composable origins retained by an inspection-enabled layout node.
699    #[cfg(feature = "inspection")]
700    pub source_trace: Rc<[cranpose_core::source_trace::SourceLocation]>,
701    /// The modifier chain of the node.
702    pub modifier: Modifier,
703    /// Padding, layout properties and offset that the modifier chain resolved to.
704    pub resolved_modifiers: ResolvedModifiers,
705    /// Draw commands, pointer input handlers, text and graphics layer data collected from the
706    /// modifier nodes.
707    pub modifier_slices: Rc<ModifierNodeSlices>,
708    /// Semantics that the modifier chain reported, if any.
709    pub semantics: Option<Rc<SemanticsConfiguration>>,
710    /// What kind of node this is.
711    pub kind: LayoutNodeKind,
712}
713
714impl LayoutNodeData {
715    /// Creates node data from its parts.
716    pub fn new(
717        modifier: Modifier,
718        resolved_modifiers: ResolvedModifiers,
719        modifier_slices: Rc<ModifierNodeSlices>,
720        semantics: Option<Rc<SemanticsConfiguration>>,
721        kind: LayoutNodeKind,
722    ) -> Self {
723        Self {
724            #[cfg(feature = "inspection")]
725            source_trace: Rc::default(),
726            modifier,
727            resolved_modifiers,
728            modifier_slices,
729            semantics,
730            kind,
731        }
732    }
733
734    /// Semantics the node's live modifier chain reported when the snapshot
735    /// was taken.
736    pub fn semantics(&self) -> Option<&SemanticsConfiguration> {
737        self.semantics.as_deref()
738    }
739
740    /// Returns the padding, layout properties and offset that the modifier chain resolved to.
741    pub fn resolved_modifiers(&self) -> ResolvedModifiers {
742        self.resolved_modifiers
743    }
744
745    /// Returns the draw, pointer input, text and graphics layer data collected from the modifier
746    /// nodes.
747    pub fn modifier_slices(&self) -> &ModifierNodeSlices {
748        &self.modifier_slices
749    }
750}
751
752/// Classification of the node captured inside a [`LayoutBox`].
753///
754/// Note: Text content is no longer represented as a distinct LayoutNodeKind.
755/// Text nodes now use `LayoutNodeKind::Layout` with their content stored in
756/// `modifier_slices.text_content()` via TextModifierNode, following Jetpack
757/// Compose's pattern where text is a modifier node capability.
758#[derive(Clone)]
759pub enum LayoutNodeKind {
760    /// A node that measures and places its children.
761    Layout,
762    /// A subcomposition boundary, such as a lazy list or a `SubcomposeLayout`.
763    Subcompose,
764    /// A non-interactive spacer.
765    Spacer,
766    /// A button node.
767    Button {
768        /// Handler that runs when the button is clicked.
769        on_click: Rc<RefCell<dyn FnMut()>>,
770    },
771    /// A node that fits no other kind.
772    Unknown,
773}
774
775impl fmt::Debug for LayoutNodeKind {
776    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
777        match self {
778            LayoutNodeKind::Layout => f.write_str("Layout"),
779            LayoutNodeKind::Subcompose => f.write_str("Subcompose"),
780            LayoutNodeKind::Spacer => f.write_str("Spacer"),
781            LayoutNodeKind::Button { .. } => f.write_str("Button"),
782            LayoutNodeKind::Unknown => f.write_str("Unknown"),
783        }
784    }
785}
786
787/// Extension trait that equips `MemoryApplier` with layout computation.
788pub trait LayoutEngine {
789    /// Measures the tree under `root` within `max_size` and returns its layout tree.
790    fn compute_layout(&mut self, root: NodeId, max_size: Size) -> Result<LayoutTree, NodeError>;
791}
792
793impl LayoutEngine for MemoryApplier {
794    fn compute_layout(&mut self, root: NodeId, max_size: Size) -> Result<LayoutTree, NodeError> {
795        let measurements = measure_layout(self, root, max_size)?;
796        measurements
797            .into_layout_tree()
798            .ok_or(NodeError::MissingContext {
799                id: root,
800                reason: "layout tree was not requested",
801            })
802    }
803}
804
805/// Result of running the measure pass for a Compose layout tree.
806#[derive(Debug, Clone)]
807pub struct LayoutMeasurements {
808    root: Rc<MeasuredNode>,
809    // Boxed: a frame that builds neither tree moves a few words, not the
810    // hundreds of bytes the trees take inline.
811    semantics: Option<Box<SemanticsTree>>,
812    layout_tree: Option<Box<LayoutTree>>,
813}
814
815impl LayoutMeasurements {
816    fn new(
817        root: Rc<MeasuredNode>,
818        semantics: Option<SemanticsTree>,
819        layout_tree: Option<LayoutTree>,
820    ) -> Self {
821        Self {
822            root,
823            semantics: semantics.map(Box::new),
824            layout_tree: layout_tree.map(Box::new),
825        }
826    }
827
828    /// Returns the measured size of the root node.
829    pub fn root_size(&self) -> Size {
830        self.root.size
831    }
832
833    /// Returns the semantics tree, or `None` if the measure options left it out.
834    pub fn semantics_tree(&self) -> Option<&SemanticsTree> {
835        self.semantics.as_deref()
836    }
837
838    /// Counts the allocations that the layout tree and the semantics tree retain.
839    pub fn debug_allocation_stats(&self) -> LayoutAllocationDebugStats {
840        let mut stats = self
841            .layout_tree
842            .as_deref()
843            .map(LayoutTree::debug_allocation_stats)
844            .unwrap_or_default();
845        if let Some(semantics) = &self.semantics {
846            record_semantics_allocation_stats(semantics.root(), &mut stats);
847        }
848        stats
849    }
850
851    /// Consumes the measurements and returns the built [`LayoutTree`], if requested.
852    pub fn into_layout_tree(self) -> Option<LayoutTree> {
853        self.layout_tree.map(|tree| *tree)
854    }
855
856    /// Returns a cloned [`LayoutTree`] for rendering/debug consumers, if requested.
857    pub fn layout_tree(&self) -> Option<LayoutTree> {
858        self.layout_tree.as_deref().cloned()
859    }
860}
861
862/// Builds a semantics tree from an existing [`LayoutTree`].
863///
864/// This is useful for consumers that need semantics on demand without forcing
865/// every layout pass to eagerly allocate a full [`SemanticsTree`].
866pub fn build_semantics_tree_from_layout_tree(layout_tree: &LayoutTree) -> SemanticsTree {
867    SemanticsTree::new(build_semantics_node_from_layout_box(
868        layout_tree.root(),
869        Point::default(),
870    ))
871}
872
873/// Builds a layout snapshot from retained layout state in the live applier tree.
874///
875/// Renderers use retained node state directly. This function exists for debug,
876/// robot, and tests that need an owned [`LayoutTree`] without forcing every
877/// layout pass to allocate one.
878pub fn build_layout_tree_from_applier(
879    applier: &mut MemoryApplier,
880    root: NodeId,
881) -> Result<Option<LayoutTree>, NodeError> {
882    let origin = layout_tree_origin(read_layout_node(applier, root, |state, _| state)?);
883    let mut child_stack = Vec::new();
884    place_layout_box(
885        applier,
886        root,
887        origin,
888        ProjectiveTransform::identity(),
889        &mut child_stack,
890    )
891    .map(|root| root.map(LayoutTree::new))
892}
893
894/// Whether any box placed under `root` has area, as
895/// [`build_layout_tree_from_applier`] would place it: the walk stops at the
896/// first such box and reads no node's modifiers or semantics.
897pub fn has_placed_content(applier: &mut MemoryApplier, root: NodeId) -> Result<bool, NodeError> {
898    walk_placed_boxes(applier, root, |_| std::ops::ControlFlow::Break(()))
899}
900
901/// The far right and bottom edges of the boxes with area placed under `root`,
902/// measured from the root's origin as [`build_layout_tree_from_applier`]
903/// places them, reading no node's modifiers or semantics. `None` while
904/// nothing under `root` has area.
905pub fn placed_content_extent(
906    applier: &mut MemoryApplier,
907    root: NodeId,
908) -> Result<Option<Size>, NodeError> {
909    let mut extent: Option<Size> = None;
910    walk_placed_boxes(applier, root, |rect| {
911        let (right, bottom) = (rect.x + rect.width, rect.y + rect.height);
912        extent = Some(extent.map_or_else(
913            || Size::new(right, bottom),
914            |extent| Size::new(extent.width.max(right), extent.height.max(bottom)),
915        ));
916        std::ops::ControlFlow::Continue(())
917    })?;
918    Ok(extent)
919}
920
921/// Hands `visit` every box with area placed under `root`, the root left out,
922/// at the rect [`build_layout_tree_from_applier`] gives it, skipping a window
923/// root's subtree and an unplaced node's, until `visit` breaks. Answers
924/// whether it did.
925fn walk_placed_boxes(
926    applier: &mut MemoryApplier,
927    root: NodeId,
928    mut visit: impl FnMut(GeometryRect) -> std::ops::ControlFlow<()>,
929) -> Result<bool, NodeError> {
930    let mut pending: Vec<(NodeId, Point)> = Vec::new();
931    let placed = read_layout_node(applier, root, |state, children| {
932        if state.is_placed() {
933            pending.extend(
934                children
935                    .iter()
936                    .map(|&child| (child, state.content_offset())),
937            );
938        }
939    })?;
940    if placed.is_none() {
941        return Ok(false);
942    }
943    while let Some((node_id, origin)) = pending.pop() {
944        if crate::modifier::is_window_root(applier, node_id) {
945            continue;
946        }
947        let rect = read_layout_node(applier, node_id, |state, children| {
948            if !state.is_placed() {
949                return None;
950            }
951            let (rect, content) = semantics_placement(&state, Some(origin));
952            pending.extend(children.iter().map(|&child| (child, content)));
953            Some(rect)
954        })?
955        .flatten();
956        if let Some(rect) = rect
957            && rect.width > 0.0
958            && rect.height > 0.0
959            && visit(rect).is_break()
960        {
961            return Ok(true);
962        }
963    }
964    Ok(false)
965}
966
967fn layout_tree_origin(root: Option<LayoutState>) -> Point {
968    let Some(state) = root else {
969        return Point::default();
970    };
971    let position = state.position();
972    Point {
973        x: -position.x,
974        y: -position.y,
975    }
976}
977
978/// Places the root at the origin, the one placement no parent makes, and
979/// names what the pass left unplaced.
980fn finish_placement(applier: &mut MemoryApplier, root: NodeId, context: &AppContext) {
981    if applier
982        .with_node::<LayoutNode, _>(root, |node| {
983            node.set_position(Point::default(), None, context);
984        })
985        .is_err()
986    {
987        let _ = applier.with_node::<SubcomposeLayoutNode, _>(root, |node| {
988            node.set_position(Point::default(), None, context);
989        });
990    }
991    if let Some(pass) = context.placement_pass().with_unplaced_nodes() {
992        record_unplaced_parents(applier, root, pass, context);
993    }
994}
995
996/// Names to the scene phase the parent of every node `pass` found placed and
997/// left unplaced: nothing about the node itself changed, so the geometry
998/// setters had nothing to report, yet its layer has to leave the scene. A
999/// pass unplaces nodes rarely, so it pays for this walk only when it did.
1000fn record_unplaced_parents(
1001    applier: &mut MemoryApplier,
1002    root: NodeId,
1003    pass: u64,
1004    context: &AppContext,
1005) {
1006    let mut parents = vec![root];
1007    let mut children = Vec::new();
1008    while let Some(parent) = parents.pop() {
1009        children.clear();
1010        if !matches!(
1011            read_layout_node(applier, parent, |_, ids| children.extend_from_slice(ids)),
1012            Ok(Some(()))
1013        ) {
1014            continue;
1015        }
1016        for &child in &children {
1017            match read_layout_node(applier, child, |state, _| state.unplaced_in(pass)) {
1018                Ok(Some(true)) => context.record_geometry_scene_node(parent),
1019                Ok(Some(false)) => parents.push(child),
1020                Ok(None) | Err(_) => {}
1021            }
1022        }
1023    }
1024}
1025
1026fn read_layout_node<R>(
1027    applier: &mut MemoryApplier,
1028    node_id: NodeId,
1029    mut read: impl FnMut(LayoutState, &[NodeId]) -> R,
1030) -> Result<Option<R>, NodeError> {
1031    read_live_layout_node(applier, node_id, |node| {
1032        node.with_children(|children| read(node.state(), children))
1033    })
1034}
1035
1036enum LiveLayoutNode<'a> {
1037    Layout(&'a LayoutNode),
1038    Subcompose(&'a SubcomposeLayoutNode),
1039}
1040
1041impl LiveLayoutNode<'_> {
1042    fn state(&self) -> LayoutState {
1043        match self {
1044            Self::Layout(node) => node.layout_state(),
1045            Self::Subcompose(node) => node.layout_state(),
1046        }
1047    }
1048
1049    fn parent(&self) -> Option<NodeId> {
1050        match self {
1051            Self::Layout(node) => node.parent(),
1052            Self::Subcompose(node) => node.parent(),
1053        }
1054    }
1055
1056    fn is_window_root(&self) -> bool {
1057        matches!(self, Self::Layout(node) if node.is_window_root())
1058    }
1059
1060    fn with_children<R>(&self, read: impl FnOnce(&[NodeId]) -> R) -> R {
1061        match self {
1062            Self::Layout(node) => read(&node.children),
1063            Self::Subcompose(node) => node.with_active_children(read),
1064        }
1065    }
1066
1067    fn semantics(&self) -> Option<SemanticsConfiguration> {
1068        match self {
1069            Self::Layout(node) => node.semantics_configuration(),
1070            Self::Subcompose(node) => node.semantics_configuration(),
1071        }
1072    }
1073}
1074
1075fn read_live_layout_node<R>(
1076    applier: &mut MemoryApplier,
1077    node_id: NodeId,
1078    mut read: impl FnMut(LiveLayoutNode<'_>) -> R,
1079) -> Result<Option<R>, NodeError> {
1080    match applier.with_node::<LayoutNode, _>(node_id, |node| read(LiveLayoutNode::Layout(node))) {
1081        Ok(value) => return Ok(Some(value)),
1082        Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => {}
1083        Err(err) => return Err(err),
1084    }
1085    match applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1086        read(LiveLayoutNode::Subcompose(node))
1087    }) {
1088        Ok(value) => Ok(Some(value)),
1089        Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => Ok(None),
1090        Err(err) => Err(err),
1091    }
1092}
1093
1094fn snapshot_node_data(
1095    applier: &mut MemoryApplier,
1096    node_id: NodeId,
1097    top_left: Point,
1098    size: Size,
1099    parent_transform: ProjectiveTransform,
1100) -> Result<(LayoutNodeData, ProjectiveTransform), NodeError> {
1101    let info = runtime_metadata_for(applier, node_id)?;
1102    let kind = layout_kind_from_metadata(node_id, &info);
1103    let RuntimeNodeMetadata {
1104        modifier,
1105        resolved_modifiers,
1106        modifier_slices,
1107        semantics,
1108        ..
1109    } = info;
1110
1111    let window_transform = modifier_slices
1112        .graphics_layer()
1113        .map_or(parent_transform, |layer| {
1114            layer_transform_to_window(
1115                parent_transform,
1116                top_left,
1117                modifier_slices.layer_bounds(size),
1118                &layer,
1119            )
1120        });
1121    modifier_slices.publish_window_geometry(top_left, window_transform, size);
1122
1123    let data = LayoutNodeData {
1124        #[cfg(feature = "inspection")]
1125        source_trace: applier
1126            .with_node::<LayoutNode, _>(node_id, |node| node.source_trace.clone())
1127            .unwrap_or_default(),
1128        modifier,
1129        resolved_modifiers,
1130        modifier_slices,
1131        semantics,
1132        kind,
1133    };
1134    Ok((data, window_transform))
1135}
1136
1137/// Places `node_id`'s box and its subtree. `child_stack` is shared by the
1138/// whole walk: each node pushes its children above its parent's, reads them
1139/// from there while its descendants push and pop above them, and pops them
1140/// when done, so no node's child list is copied out of the applier.
1141fn place_layout_box(
1142    applier: &mut MemoryApplier,
1143    node_id: NodeId,
1144    parent_content_origin: Point,
1145    parent_transform: ProjectiveTransform,
1146    child_stack: &mut Vec<NodeId>,
1147) -> Result<Option<LayoutBox>, NodeError> {
1148    let first_child = child_stack.len();
1149    let Some(state) = read_layout_node(applier, node_id, |state, children| {
1150        if state.is_placed() {
1151            child_stack.extend_from_slice(children);
1152        }
1153        state
1154    })?
1155    else {
1156        return Ok(None);
1157    };
1158    if !state.is_placed() {
1159        return Ok(None);
1160    }
1161
1162    let top_left = Point {
1163        x: parent_content_origin.x + state.position().x,
1164        y: parent_content_origin.y + state.position().y,
1165    };
1166    let rect = GeometryRect {
1167        x: top_left.x,
1168        y: top_left.y,
1169        width: state.size().width,
1170        height: state.size().height,
1171    };
1172    let (data, window_transform) =
1173        snapshot_node_data(applier, node_id, top_left, state.size(), parent_transform)?;
1174    let child_origin = Point {
1175        x: top_left.x + state.content_offset().x,
1176        y: top_left.y + state.content_offset().y,
1177    };
1178    let end = child_stack.len();
1179    let mut children = Vec::with_capacity(end - first_child);
1180    for index in first_child..end {
1181        let child_id = child_stack[index];
1182        if crate::modifier::is_window_root(applier, child_id) {
1183            continue;
1184        }
1185        if let Some(child) = place_layout_box(
1186            applier,
1187            child_id,
1188            child_origin,
1189            window_transform,
1190            child_stack,
1191        )? {
1192            children.push(child);
1193        }
1194    }
1195    child_stack.truncate(first_child);
1196
1197    Ok(Some(LayoutBox {
1198        node_generation: applier.node_generation(node_id),
1199        ..LayoutBox::new(node_id, rect, state.content_offset(), data, children)
1200    }))
1201}
1202
1203/// The modal the semantics tree of `root` would be rooted at, found without
1204/// building the tree: the topmost placed, visible modal that takes space,
1205/// or `None` when no modal is open. Unlike a tree update, it leaves the
1206/// nodes' semantics dirty flags alone.
1207pub fn top_modal_from_applier(
1208    applier: &mut MemoryApplier,
1209    root: NodeId,
1210) -> Result<Option<NodeId>, NodeError> {
1211    // One depth-first walk on a shared stack, last child first, with a
1212    // modal's own step below its children's: the first modal step popped is
1213    // the modal drawn on top. It runs every frame, so no node's children are
1214    // copied and each node is looked up once.
1215    enum Step {
1216        Enter { node: NodeId, child: bool },
1217        Modal(NodeId),
1218    }
1219
1220    fn push_placed(
1221        steps: &mut Vec<Step>,
1222        node: NodeId,
1223        reach: cranpose_foundation::SemanticsReach,
1224        size: Size,
1225        children: impl IntoIterator<Item = NodeId>,
1226    ) {
1227        if reach.hidden {
1228            return;
1229        }
1230        if reach.is_modal && modal_takes_space(size) {
1231            steps.push(Step::Modal(node));
1232        }
1233        steps.extend(
1234            children
1235                .into_iter()
1236                .map(|node| Step::Enter { node, child: true }),
1237        );
1238    }
1239
1240    let mut steps = vec![Step::Enter {
1241        node: root,
1242        child: false,
1243    }];
1244    while let Some(step) = steps.pop() {
1245        let (node_id, child) = match step {
1246            Step::Modal(node) => return Ok(Some(node)),
1247            Step::Enter { node, child } => (node, child),
1248        };
1249        let node = match applier.get_mut(node_id) {
1250            Ok(node) => node.as_any_mut(),
1251            Err(NodeError::Missing { .. }) => continue,
1252            Err(error) => return Err(error),
1253        };
1254        if let Some(layout) = node.downcast_mut::<LayoutNode>() {
1255            let state = layout.layout_state();
1256            if state.is_placed() && !(child && layout.is_window_root()) {
1257                let children = layout.children.iter().copied();
1258                push_placed(
1259                    &mut steps,
1260                    node_id,
1261                    layout.semantics_reach(),
1262                    state.size(),
1263                    children,
1264                );
1265            }
1266        } else if let Some(subcompose) = node.downcast_mut::<SubcomposeLayoutNode>() {
1267            let state = subcompose.layout_state();
1268            if state.is_placed() {
1269                let reach = subcompose.semantics_reach();
1270                subcompose.with_active_children(|children| {
1271                    push_placed(
1272                        &mut steps,
1273                        node_id,
1274                        reach,
1275                        state.size(),
1276                        children.iter().copied(),
1277                    );
1278                });
1279            }
1280        }
1281    }
1282    Ok(None)
1283}
1284
1285/// Selects which trees [`measure_layout_with_options`] builds.
1286#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1287pub struct MeasureLayoutOptions {
1288    /// Build the semantics tree.
1289    pub collect_semantics: bool,
1290    /// Build the layout tree.
1291    pub build_layout_tree: bool,
1292}
1293
1294impl Default for MeasureLayoutOptions {
1295    fn default() -> Self {
1296        Self {
1297            collect_semantics: true,
1298            build_layout_tree: true,
1299        }
1300    }
1301}
1302
1303/// Check if a node or any of its descendants needs measure (selective measure optimization).
1304/// This can be used by the app shell to skip layout when the tree is clean.
1305///
1306/// O(1) check - just looks at root's dirty flag.
1307/// Works because all mutation paths bubble dirty flags to root via composer commands.
1308///
1309/// Returns Result to force caller to handle errors explicitly. No more unwrap_or(true) safety net.
1310pub fn tree_needs_layout(applier: &mut dyn Applier, root: NodeId) -> Result<bool, NodeError> {
1311    Ok(applier.get_mut(root)?.layout_dirty())
1312}
1313
1314/// Check if the root semantics snapshot is dirty.
1315///
1316/// Semantics invalidations bubble to the root the same way layout invalidations do,
1317/// so a root check is sufficient to determine whether the next layout pass needs to
1318/// rebuild semantic data even when geometry is otherwise unchanged.
1319pub fn tree_needs_semantics(applier: &mut dyn Applier, root: NodeId) -> Result<bool, NodeError> {
1320    Ok(applier.get_mut(root)?.needs_semantics())
1321}
1322
1323#[cfg(test)]
1324pub(crate) fn bubble_layout_dirty(applier: &mut MemoryApplier, node_id: NodeId) {
1325    cranpose_core::bubble_layout_dirty(applier as &mut dyn Applier, node_id);
1326}
1327
1328/// Runs the measure phase for the subtree rooted at `root`.
1329pub fn measure_layout(
1330    applier: &mut MemoryApplier,
1331    root: NodeId,
1332    max_size: Size,
1333) -> Result<LayoutMeasurements, NodeError> {
1334    measure_layout_with_options(applier, root, max_size, MeasureLayoutOptions::default())
1335}
1336
1337/// Runs the measure phase for the subtree rooted at `root` and builds only the trees that `options`
1338/// select.
1339pub fn measure_layout_with_options(
1340    applier: &mut MemoryApplier,
1341    root: NodeId,
1342    max_size: Size,
1343    options: MeasureLayoutOptions,
1344) -> Result<LayoutMeasurements, NodeError> {
1345    let mut stages = LayoutStages::start(layout_measure_telemetry_threshold_ms().is_some());
1346    let context = crate::render_state::require_current_app_context("a layout pass");
1347    context.begin_text_layout_pass();
1348    context.placement_pass().begin();
1349    process_pending_layout_repasses(&context, applier, root)?;
1350    stages.reached();
1351
1352    let constraints = Constraints {
1353        min_width: 0.0,
1354        max_width: max_size.width,
1355        min_height: 0.0,
1356        max_height: max_size.height,
1357    };
1358
1359    let (needs_remeasure, _needs_semantics, cached_epoch) = match applier
1360        .with_node::<LayoutNode, _>(root, |node| {
1361            (
1362                node.needs_measure() || Node::descendant_needs_measure(node),
1363                node.needs_semantics(),
1364                node.cache_handles().epoch(),
1365            )
1366        }) {
1367        Ok(tuple) => tuple,
1368        Err(NodeError::TypeMismatch { .. }) => {
1369            let node = applier.get_mut(root)?;
1370            let measure_dirty = node.needs_measure() || node.descendant_needs_measure();
1371            let semantics_dirty = node.needs_semantics();
1372            (measure_dirty, semantics_dirty, 0)
1373        }
1374        Err(err) => return Err(err),
1375    };
1376
1377    let epoch = if needs_remeasure {
1378        context.next_layout_cache_epoch()
1379    } else if cached_epoch != 0 {
1380        cached_epoch
1381    } else {
1382        context.current_layout_cache_epoch()
1383    };
1384
1385    let guard = ApplierSlotGuard::new(applier, &context);
1386    let applier_host = guard.host();
1387    stages.reached();
1388
1389    let builder = LayoutBuilder::new_with_epoch(Rc::clone(applier_host), epoch, &context);
1390    stages.reached();
1391
1392    let measured = builder
1393        .state
1394        .measure_root(root, normalize_constraints(constraints))?;
1395    stages.reached();
1396
1397    if let Ok(mut applier) = applier_host.try_borrow_typed() {
1398        finish_placement(&mut applier, root, &context);
1399    }
1400    stages.reached();
1401
1402    let (layout_tree, semantics) = {
1403        let mut applier_ref = applier_host.borrow_typed();
1404        let layout_tree = if options.build_layout_tree {
1405            Some(build_layout_tree(&mut applier_ref, &measured)?)
1406        } else {
1407            None
1408        };
1409        let semantics = if options.collect_semantics {
1410            let semantics_tree = if let Some(layout_tree) = layout_tree.as_ref() {
1411                clear_semantics_dirty_flags(&mut applier_ref, &measured)?;
1412                build_semantics_tree_from_layout_tree(layout_tree)
1413            } else {
1414                build_semantics_tree_from_live_nodes(&mut applier_ref, &measured)?
1415            };
1416            Some(semantics_tree)
1417        } else {
1418            None
1419        };
1420        (layout_tree, semantics)
1421    };
1422    stages.reached();
1423
1424    drop(builder);
1425    stages.reached();
1426
1427    drop(guard);
1428    stages.reached();
1429
1430    log_layout_measure_telemetry(root, &stages);
1431
1432    Ok(LayoutMeasurements::new(measured, semantics, layout_tree))
1433}
1434
1435fn process_pending_layout_repasses(
1436    context: &AppContext,
1437    applier: &mut MemoryApplier,
1438    root: NodeId,
1439) -> Result<(), NodeError> {
1440    for node_id in context.take_modifier_slice_repass_nodes() {
1441        if let Ok(node) = applier.get_mut(node_id) {
1442            let any = node.as_any_mut();
1443            if let Some(layout) = any.downcast_mut::<crate::widgets::nodes::LayoutNode>() {
1444                layout.mark_modifier_slices_dirty();
1445            } else if let Some(subcompose) =
1446                any.downcast_mut::<crate::subcompose_layout::SubcomposeLayoutNode>()
1447            {
1448                subcompose.mark_modifier_slices_dirty();
1449            }
1450        }
1451    }
1452    let measure_repass_nodes = context.take_measure_repass_nodes();
1453    let repass_nodes = context.take_layout_repass_nodes();
1454    if measure_repass_nodes.is_empty() && repass_nodes.is_empty() {
1455        return Ok(());
1456    }
1457    for node_id in measure_repass_nodes {
1458        cranpose_core::bubble_measure_dirty(applier as &mut dyn Applier, node_id);
1459    }
1460    for node_id in repass_nodes {
1461        cranpose_core::bubble_layout_dirty(applier as &mut dyn Applier, node_id);
1462    }
1463    applier.get_mut(root)?.mark_descendant_needs_layout(false);
1464    Ok(())
1465}
1466
1467/// A layout pass's builder, with the frame arena it took from `context` and
1468/// gives back when dropped.
1469struct LayoutBuilder<'a> {
1470    state: Rc<LayoutBuilderState>,
1471    context: &'a AppContext,
1472}
1473
1474impl<'a> LayoutBuilder<'a> {
1475    fn new_with_epoch(
1476        applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1477        epoch: u64,
1478        context: &'a Rc<AppContext>,
1479    ) -> Self {
1480        Self {
1481            state: Rc::new(LayoutBuilderState::new_with_epoch(
1482                applier,
1483                epoch,
1484                Rc::clone(context),
1485            )),
1486            context,
1487        }
1488    }
1489}
1490
1491impl Drop for LayoutBuilder<'_> {
1492    fn drop(&mut self) {
1493        if Rc::strong_count(&self.state) != 1 {
1494            return;
1495        }
1496        let Ok(mut frame_arena) = self.state.frame_arena.try_borrow_mut() else {
1497            return;
1498        };
1499        self.context
1500            .replace_layout_frame_arena(std::mem::take(&mut *frame_arena));
1501    }
1502}
1503
1504struct LayoutBuilderState {
1505    applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1506    runtime_handle: RefCell<Option<RuntimeHandle>>,
1507    cache_epoch: u64,
1508    cache_floor: u64,
1509    frame_arena: RefCell<FrameLayoutArena>,
1510    /// The context the pass lays out in, which takes the nodes whose
1511    /// geometry it changed.
1512    context: Rc<AppContext>,
1513    /// The threshold of the measure telemetry, read once a pass: `None`
1514    /// while the telemetry is off.
1515    measure_telemetry_ms: Option<f64>,
1516}
1517
1518struct LayoutRuntimeFrameBindingCleanup<'a> {
1519    state: &'a RefCell<LayoutRuntimeState>,
1520}
1521
1522impl Drop for LayoutRuntimeFrameBindingCleanup<'_> {
1523    fn drop(&mut self) {
1524        self.state.borrow().unbind_children();
1525    }
1526}
1527
1528enum LayoutNodeVisit<'a> {
1529    Cached(Rc<MeasuredNode>),
1530    /// Only nodes below this one changed: its measurement holds unless a
1531    /// changed child measures differently.
1532    Keep(KeptNode),
1533    Measure(LayoutNodeMeasure<'a>),
1534}
1535
1536/// A node whose measurement may hold, with the parts of it the keep reads
1537/// and writes, so the keep needs no lookup of the node.
1538struct KeptNode {
1539    measured: Rc<MeasuredNode>,
1540    runtime_state: Rc<RefCell<LayoutRuntimeState>>,
1541    cache: LayoutNodeCacheHandles,
1542    /// Whether a child that measures to another size leaves the node as it
1543    /// is.
1544    ignores_child_sizes: bool,
1545}
1546
1547/// A kept measurement after the walk over its changed children: `resized`
1548/// when one of them measured to another size that the node ignores.
1549struct KeptChildren {
1550    measured: Rc<MeasuredNode>,
1551    resized: bool,
1552}
1553
1554/// What measuring one changed child of a kept node again needs.
1555#[derive(Clone, Copy)]
1556struct ChangedChild {
1557    constraints: Constraints,
1558    placed: bool,
1559}
1560
1561/// What the walk over a kept measurement finds of one child.
1562enum ChildChange {
1563    Unchanged,
1564    Changed(ChangedChild),
1565    /// The node has to run its policy.
1566    Refuse,
1567}
1568
1569/// A changed child of a kept node as a layout pass finds it, from a layout
1570/// node or a subcompose node.
1571struct ChildView {
1572    self_dirty: bool,
1573    /// The child's parent data, read only when the child changed itself:
1574    /// only its own modifiers give it.
1575    parent_data: Option<cranpose_ui_layout::ParentData>,
1576    /// The constraints the child's own cache holds.
1577    cached_constraints: Option<Constraints>,
1578    read_intrinsics: bool,
1579    placed: bool,
1580}
1581
1582impl ChildView {
1583    /// The child, when it or a node below it changed.
1584    fn of(
1585        node: &dyn Node,
1586        cache: &LayoutNodeCacheHandles,
1587        parent_data: &dyn Fn() -> cranpose_ui_layout::ParentData,
1588        placed: bool,
1589    ) -> Option<Self> {
1590        let self_dirty = node.needs_measure() || node.needs_layout();
1591        if !self_dirty && !node.descendant_needs_layout() {
1592            return None;
1593        }
1594        Some(Self {
1595            self_dirty,
1596            parent_data: self_dirty.then(parent_data),
1597            cached_constraints: cache.measured_constraints(),
1598            read_intrinsics: cache.has_intrinsics(),
1599            placed,
1600        })
1601    }
1602}
1603
1604struct LayoutNodeMeasure<'a> {
1605    runtime_state: Rc<RefCell<LayoutRuntimeState>>,
1606    chain: ModifierChainInputs,
1607    pools: VecPools<'a>,
1608    spare: MeasuredSpare,
1609}
1610
1611impl LayoutBuilderState {
1612    fn new_with_epoch(
1613        applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1614        epoch: u64,
1615        context: Rc<AppContext>,
1616    ) -> Self {
1617        let runtime_handle = applier.borrow_typed().runtime_handle();
1618
1619        Self {
1620            applier,
1621            runtime_handle: RefCell::new(runtime_handle),
1622            cache_epoch: epoch,
1623            cache_floor: context.layout_cache_floor(),
1624            frame_arena: RefCell::new(context.take_layout_frame_arena()),
1625            context,
1626            measure_telemetry_ms: layout_measure_telemetry_threshold_ms(),
1627        }
1628    }
1629
1630    fn with_applier_result<R>(
1631        &self,
1632        f: impl FnOnce(&mut MemoryApplier) -> Result<R, NodeError>,
1633    ) -> Result<R, NodeError> {
1634        let Ok(mut applier) = self.applier.try_borrow_typed() else {
1635            return Err(NodeError::MissingContext {
1636                id: NodeId::default(),
1637                reason: "applier already borrowed",
1638            });
1639        };
1640        f(&mut applier)
1641    }
1642
1643    fn measure_subcompose_node(
1644        self: &Rc<Self>,
1645        node_id: NodeId,
1646        constraints: Constraints,
1647    ) -> Result<(&'static str, Rc<MeasuredNode>), NodeError> {
1648        self.clear_subcompose_placed(node_id);
1649        if let Some(cached) = self.subcompose_measurement_to_keep(node_id, constraints)
1650            && let Some(kept) = self.keep_subcompose_measurement(node_id, constraints, &cached)?
1651        {
1652            return Ok(("subcompose kept", kept));
1653        }
1654        Ok(match self.try_measure_subcompose(node_id, constraints)? {
1655            Some(measured) => {
1656                self.store_subcompose_measurement(node_id, constraints, &measured);
1657                ("subcompose", measured)
1658            }
1659            None => (
1660                "fallback",
1661                Rc::new(MeasuredNode::new(
1662                    node_id,
1663                    Size::default(),
1664                    Point { x: 0.0, y: 0.0 },
1665                    Point::default(),
1666                    Vec::new(),
1667                )),
1668            ),
1669        })
1670    }
1671
1672    /// The measurement of a subcompose node whose own inputs did not change
1673    /// since it measured at `constraints`, as for a layout node: its policy
1674    /// does not run, so its content does not compose again.
1675    fn subcompose_measurement_to_keep(
1676        &self,
1677        node_id: NodeId,
1678        constraints: Constraints,
1679    ) -> Option<Rc<MeasuredNode>> {
1680        let mut applier = self.applier.try_borrow_typed().ok()?;
1681        applier
1682            .with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1683                if node.needs_measure() || Node::needs_layout(node) {
1684                    return None;
1685                }
1686                let cache = node.cache_handles();
1687                if cache.epoch() < self.cache_floor {
1688                    return None;
1689                }
1690                cache.get_measurement(constraints)
1691            })
1692            .ok()
1693            .flatten()
1694    }
1695
1696    /// Keeps a subcompose node's measurement as [`Self::keep_measurement`]
1697    /// keeps a layout node's. A subcompose node holds no record of what its
1698    /// policy gave each child, so a changed child must have only changed
1699    /// nodes below it, and measures again at the constraints its own cache
1700    /// holds.
1701    fn keep_subcompose_measurement(
1702        self: &Rc<Self>,
1703        node_id: NodeId,
1704        constraints: Constraints,
1705        cached: &Rc<MeasuredNode>,
1706    ) -> Result<Option<Rc<MeasuredNode>>, NodeError> {
1707        let kept = self.remeasure_changed_children(
1708            cached,
1709            false,
1710            |child_id| self.subcompose_child_change(child_id),
1711            |child_id| self.mark_measured_without_policy(child_id),
1712        )?;
1713        let Some(KeptChildren { measured: kept, .. }) = kept else {
1714            return Ok(None);
1715        };
1716        self.with_applier_result(|applier| {
1717            applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1718                node.cache_handles()
1719                    .store_measurement(constraints, Rc::clone(&kept));
1720                node.clear_needs_layout();
1721            })
1722        })?;
1723        Ok(Some(kept))
1724    }
1725
1726    /// What the walk over a kept subcompose node finds of a child. A changed
1727    /// child refuses the keep when it changed itself, a parent read its
1728    /// intrinsic sizes, or its cache holds no constraints.
1729    fn subcompose_child_change(&self, child_id: NodeId) -> Result<ChildChange, NodeError> {
1730        self.child_change(child_id, |view| {
1731            match view.cached_constraints.filter(|_| !view.self_dirty) {
1732                Some(constraints) if !view.read_intrinsics => ChildChange::Changed(ChangedChild {
1733                    constraints,
1734                    placed: view.placed,
1735                }),
1736                _ => ChildChange::Refuse,
1737            }
1738        })
1739    }
1740
1741    /// What the walk finds of a child: unchanged when neither it nor a node
1742    /// below it changed, otherwise what `decide` makes of it.
1743    fn child_change(
1744        &self,
1745        child_id: NodeId,
1746        decide: impl FnOnce(ChildView) -> ChildChange,
1747    ) -> Result<ChildChange, NodeError> {
1748        let Ok(mut applier) = self.applier.try_borrow_typed() else {
1749            return Ok(ChildChange::Refuse);
1750        };
1751        Ok(
1752            match read_layout_child(&mut applier, child_id, ChildView::of)? {
1753                None => ChildChange::Refuse,
1754                Some(None) => ChildChange::Unchanged,
1755                Some(Some(view)) => decide(view),
1756            },
1757        )
1758    }
1759
1760    /// Marks a child a subcompose node measured again without its policy, so
1761    /// the policy checks it when it next runs: it may keep measurements of
1762    /// its own, as a lazy list keeps its items'.
1763    fn mark_measured_without_policy(&self, child_id: NodeId) {
1764        let Ok(mut applier) = self.applier.try_borrow_typed() else {
1765            return;
1766        };
1767        if let Ok(node) = applier.get_mut(child_id) {
1768            node.mark_descendant_needs_layout(true);
1769        }
1770    }
1771
1772    fn clear_subcompose_placed(&self, node_id: NodeId) {
1773        let Ok(mut applier) = self.applier.try_borrow_typed() else {
1774            return;
1775        };
1776        let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1777            node.clear_placed(&self.context);
1778        });
1779    }
1780
1781    fn measure_node(
1782        self: &Rc<Self>,
1783        node_id: NodeId,
1784        constraints: Constraints,
1785    ) -> Result<Rc<MeasuredNode>, NodeError> {
1786        let Some(threshold_ms) = self.measure_telemetry_ms else {
1787            return self
1788                .measure_node_untimed(node_id, constraints)
1789                .map(|(_, measured)| measured);
1790        };
1791        let start = Instant::now();
1792        let (kind, measured) = self.measure_node_untimed(node_id, constraints)?;
1793        log_node_measure_telemetry(kind, node_id, constraints, &measured, (threshold_ms, start));
1794        Ok(measured)
1795    }
1796
1797    /// The measurement of `node_id` and the kind of node it is.
1798    fn measure_node_untimed(
1799        self: &Rc<Self>,
1800        node_id: NodeId,
1801        constraints: Constraints,
1802    ) -> Result<(&'static str, Rc<MeasuredNode>), NodeError> {
1803        if let Some(measured) = self.measure_layout_node(node_id, constraints)? {
1804            return Ok(("layout", measured));
1805        }
1806        self.measure_subcompose_node(node_id, constraints)
1807    }
1808
1809    fn try_measure_subcompose(
1810        self: &Rc<Self>,
1811        node_id: NodeId,
1812        constraints: Constraints,
1813    ) -> Result<Option<Rc<MeasuredNode>>, NodeError> {
1814        let (node_handle, resolved_modifiers, spare) = {
1815            let Ok(mut applier) = self.applier.try_borrow_typed() else {
1816                return Ok(None);
1817            };
1818            let node = match applier.get_mut(node_id) {
1819                Ok(node) => node,
1820                Err(NodeError::Missing { .. }) => return Ok(None),
1821                Err(err) => return Err(err),
1822            };
1823            let any = node.as_any_mut();
1824            if let Some(subcompose) =
1825                any.downcast_mut::<crate::subcompose_layout::SubcomposeLayoutNode>()
1826            {
1827                let handle = subcompose.handle();
1828                let resolved_modifiers = handle
1829                    .resolved_modifiers()
1830                    .on_device_grid(subcompose.density().density());
1831                let spare = MeasuredSpare::take(subcompose.cache_handles());
1832                (handle, resolved_modifiers, spare)
1833            } else {
1834                return Ok(None);
1835            }
1836        };
1837
1838        let runtime_handle = {
1839            let mut runtime_handle = self.runtime_handle.borrow_mut();
1840            if runtime_handle.is_none()
1841                && let Ok(applier) = self.applier.try_borrow_typed()
1842            {
1843                *runtime_handle = applier.runtime_handle();
1844            }
1845            runtime_handle.clone().ok_or(NodeError::MissingContext {
1846                id: node_id,
1847                reason: "runtime handle required for subcomposition",
1848            })?
1849        };
1850
1851        let props = resolved_modifiers.layout_properties();
1852        let padding = resolved_modifiers.padding();
1853        let offset = resolved_modifiers.offset();
1854        let mut inner_constraints = normalize_constraints(subtract_padding(constraints, padding));
1855
1856        if let DimensionConstraint::Points(width) = props.width() {
1857            let constrained_width = width - padding.horizontal_sum();
1858            inner_constraints.max_width = inner_constraints.max_width.min(constrained_width);
1859            inner_constraints.min_width = inner_constraints.min_width.min(constrained_width);
1860        }
1861        if let DimensionConstraint::Points(height) = props.height() {
1862            let constrained_height = height - padding.vertical_sum();
1863            inner_constraints.max_height = inner_constraints.max_height.min(constrained_height);
1864            inner_constraints.min_height = inner_constraints.min_height.min(constrained_height);
1865        }
1866
1867        let applier_host: Rc<dyn ApplierHost> = Rc::clone(&self.applier) as Rc<dyn ApplierHost>;
1868        let measure_error = RefCell::new(None);
1869        let measured_children = node_handle.measured_children_scratch();
1870
1871        let measure_result = node_handle.measure_with_callbacks(
1872            &applier_host,
1873            &runtime_handle,
1874            node_id,
1875            inner_constraints,
1876            MeasureCallbacks {
1877                measurer: Box::new(|child_id: NodeId, child_constraints: Constraints| {
1878                    match self.measure_node(child_id, child_constraints) {
1879                        Ok(measured) => {
1880                            measured_children
1881                                .borrow_mut()
1882                                .insert(child_id, Rc::clone(&measured));
1883                            let size = measured.size_for_parent();
1884                            Placeable::value(size.width, size.height, child_id)
1885                                .with_alignment_lines(measured.alignment_lines_for_parent())
1886                        }
1887                        Err(err) => {
1888                            let mut slot = measure_error.borrow_mut();
1889                            if slot.is_none() {
1890                                *slot = Some(err);
1891                            }
1892                            Placeable::value(0.0, 0.0, child_id)
1893                        }
1894                    }
1895                }),
1896                retained_measure_lookup: Box::new(|child_id| {
1897                    measured_children.borrow().get(&child_id).cloned()
1898                }),
1899                error: &measure_error,
1900            },
1901        )?;
1902
1903        if let Some(err) = measure_error.borrow_mut().take() {
1904            return Err(err);
1905        }
1906
1907        let cranpose_ui_layout::MeasureResult {
1908            size: measured_size,
1909            alignment_lines: explicit_lines,
1910            placements,
1911        } = measure_result;
1912
1913        let mut width = measured_size.width + padding.horizontal_sum();
1914        let mut height = measured_size.height + padding.vertical_sum();
1915
1916        width = resolve_dimension(
1917            width,
1918            props.width(),
1919            props.min_width(),
1920            props.max_width(),
1921            constraints.min_width,
1922            constraints.max_width,
1923        );
1924        height = resolve_dimension(
1925            height,
1926            props.height(),
1927            props.min_height(),
1928            props.max_height(),
1929            constraints.min_height,
1930            constraints.max_height,
1931        );
1932
1933        let MeasuredSpare {
1934            node: spare,
1935            mut children,
1936        } = spare;
1937        children.reserve_exact(placements.len());
1938        let mut alignment_lines = AlignmentLines::default();
1939        let mut measured_children_by_id = measured_children.borrow_mut();
1940
1941        // One borrow of the applier places every child; measuring a child
1942        // the pass did not measure borrows it on its own.
1943        let mut applier = self.applier.try_borrow_typed().ok();
1944        if let Some(applier) = applier.as_mut() {
1945            let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |parent_node| {
1946                parent_node.set_measured_size(Size { width, height }, &self.context);
1947                parent_node.clear_needs_measure();
1948                parent_node.clear_needs_layout();
1949            });
1950        }
1951
1952        // A lazy policy placed its items' roots with their measurements; the
1953        // other placements are looked up.
1954        let placed_roots = node_handle.take_placed_roots();
1955        let mut carried = PlacedRootMeasurements::new(&placed_roots);
1956        for placement in &placements {
1957            let looked_up;
1958            let child: &MeasuredNode = if let Some(measured) = carried.next_measurement() {
1959                measured
1960            } else {
1961                looked_up =
1962                    if let Some(measured) = measured_children_by_id.remove(&placement.node_id) {
1963                        measured
1964                    } else {
1965                        drop(applier.take());
1966                        let measured = self.measure_node(placement.node_id, inner_constraints)?;
1967                        applier = self.applier.try_borrow_typed().ok();
1968                        measured
1969                    };
1970                &looked_up
1971            };
1972            let policy_position = Point {
1973                x: padding.left + placement.x,
1974                y: padding.top + placement.y,
1975            };
1976            let retained_position = Point {
1977                x: policy_position.x + child.offset.x,
1978                y: policy_position.y + child.offset.y,
1979            };
1980            alignment_lines.merge(
1981                child
1982                    .alignment_lines_for_parent()
1983                    .translated(policy_position.y),
1984            );
1985
1986            if let Some(applier) = applier.as_mut()
1987                && applier
1988                    .with_node::<LayoutNode, _>(placement.node_id, |node| {
1989                        node.set_position(retained_position, Some(node_id), &self.context);
1990                    })
1991                    .is_err()
1992            {
1993                let _ = applier.with_node::<SubcomposeLayoutNode, _>(placement.node_id, |node| {
1994                    node.set_position(retained_position, Some(node_id), &self.context);
1995                });
1996            }
1997
1998            children.push(MeasuredChild::new(child, policy_position));
1999        }
2000        drop(applier);
2001
2002        node_handle.recycle_placed_roots(placed_roots);
2003        node_handle.recycle_placement_scratch(placements);
2004
2005        Ok(Some(
2006            MeasuredNode::new(
2007                node_id,
2008                Size { width, height },
2009                offset,
2010                Point::default(),
2011                children,
2012            )
2013            .with_alignment_lines(
2014                alignment_lines
2015                    .with_overrides(explicit_lines.translated(padding.top))
2016                    .translated(offset.y),
2017            )
2018            .into_rc(spare),
2019        ))
2020    }
2021
2022    fn measure_layout_node(
2023        self: &Rc<Self>,
2024        node_id: NodeId,
2025        constraints: Constraints,
2026    ) -> Result<Option<Rc<MeasuredNode>>, NodeError> {
2027        let mut keep = true;
2028        let (mut applier, measure) = loop {
2029            let Ok(mut applier) = self.applier.try_borrow_typed() else {
2030                return Ok(None);
2031            };
2032            match applier.with_node::<LayoutNode, _>(node_id, |node| {
2033                self.visit_layout_node(node, constraints, keep)
2034            }) {
2035                Ok(LayoutNodeVisit::Measure(measure)) => break (applier, measure),
2036                Ok(LayoutNodeVisit::Cached(measured)) => return Ok(Some(measured)),
2037                Ok(LayoutNodeVisit::Keep(node)) => {
2038                    drop(applier);
2039                    if let Some(kept) = self.keep_measurement(constraints, node)? {
2040                        return Ok(Some(kept));
2041                    }
2042                    keep = false;
2043                }
2044                Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => return Ok(None),
2045                Err(err) => return Err(err),
2046            }
2047        };
2048        let LayoutNodeMeasure {
2049            runtime_state,
2050            chain,
2051            mut pools,
2052            spare,
2053        } = measure;
2054
2055        let _frame_binding_cleanup = LayoutRuntimeFrameBindingCleanup {
2056            state: &runtime_state,
2057        };
2058        self.bind_layout_children(
2059            &mut applier,
2060            (node_id, &runtime_state),
2061            &pools.child_ids,
2062            ChildPass::Measure,
2063        )?;
2064        drop(applier);
2065        pools.child_ids.clear();
2066
2067        let runtime_state = runtime_state.borrow();
2068        let measurement = self.measure_through_modifier_chain(
2069            node_id,
2070            &runtime_state,
2071            chain,
2072            constraints,
2073            &mut pools.placements,
2074            &mut pools.child_ids,
2075        );
2076
2077        if let Some(err) = runtime_state.take_child_error() {
2078            for child_state in runtime_state.child_states() {
2079                child_state.measured.take();
2080            }
2081            self.with_applier_result(|applier| {
2082                applier.with_node::<LayoutNode, _>(node_id, |node| {
2083                    if runtime_state.write_node_geometry(node, &measurement) {
2084                        node.note_geometry_change(node_id, &self.context);
2085                    }
2086                })
2087            })
2088            .ok();
2089            return Err(err);
2090        }
2091
2092        let MeasuredSpare {
2093            node: spare,
2094            mut children,
2095        } = spare;
2096        runtime_state.measured_children(
2097            &pools.placements,
2098            &pools.child_ids,
2099            measurement.content_offset,
2100            &mut children,
2101        );
2102        let measured = MeasuredNode::new(
2103            node_id,
2104            measurement.size,
2105            measurement.offset,
2106            measurement.content_offset,
2107            children,
2108        )
2109        .with_alignment_lines(measurement.alignment_lines)
2110        .with_window_root(measurement.window_root)
2111        .into_rc(spare);
2112
2113        self.with_applier_result(|applier| {
2114            applier.with_node::<LayoutNode, _>(node_id, |node| {
2115                node.cache_handles().store_held_measurement(
2116                    constraints,
2117                    Rc::clone(&measured),
2118                    measurement.hold,
2119                    measurement.ignores_child_sizes,
2120                );
2121                if runtime_state.write_node_geometry(node, &measurement) {
2122                    node.note_geometry_change(node_id, &self.context);
2123                }
2124                node.clear_needs_measure();
2125                node.clear_needs_layout();
2126                node.set_measured_size(measurement.size, &self.context);
2127                node.set_content_offset(measurement.content_offset);
2128            })
2129        })
2130        .ok();
2131
2132        Ok(Some(measured))
2133    }
2134
2135    /// The intrinsic size `kind` names of a layout node, through its modifier
2136    /// chain and measure policy, as Compose computes it: no measure, no
2137    /// placement, and the node's measurement cache stays as it was. `None`
2138    /// when the node is not a layout node.
2139    fn layout_node_intrinsic(
2140        self: &Rc<Self>,
2141        node_id: NodeId,
2142        kind: IntrinsicKind,
2143    ) -> Result<Option<f32>, NodeError> {
2144        let Ok(mut applier) = self.applier.try_borrow_typed() else {
2145            return Ok(None);
2146        };
2147        let mut pools = VecPools::acquire(&self.frame_arena);
2148        let bound = applier.with_node::<LayoutNode, _>(node_id, |node| {
2149            let runtime_state = node.layout_runtime_state_handle();
2150            let chain = runtime_state.borrow_mut().bind_node(node);
2151            pools.child_ids.extend_from_slice(&node.children);
2152            (runtime_state, chain)
2153        });
2154        let (runtime_state, chain) = match bound {
2155            Ok(bound) => bound,
2156            Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => return Ok(None),
2157            Err(err) => return Err(err),
2158        };
2159        let _frame_binding_cleanup = LayoutRuntimeFrameBindingCleanup {
2160            state: &runtime_state,
2161        };
2162        self.bind_layout_children(
2163            &mut applier,
2164            (node_id, &runtime_state),
2165            &pools.child_ids,
2166            ChildPass::Intrinsics,
2167        )?;
2168        drop(applier);
2169        pools.child_ids.clear();
2170
2171        let runtime_state = runtime_state.borrow();
2172        let value = if chain.uses_chain {
2173            let scope = crate::density::DensityMeasureScope::new(chain.density);
2174            let frame = CoordinatorFrame::new(
2175                &runtime_state.measure_policy,
2176                &scope,
2177                runtime_state.child_measurables(),
2178                runtime_state.child_states(),
2179                &mut pools.placements,
2180                &mut pools.child_ids,
2181            );
2182            runtime_state
2183                .coordinator_chain
2184                .intrinsic_from(0, &frame, kind)
2185        } else {
2186            policy_intrinsic(
2187                runtime_state.measure_policy.as_ref(),
2188                runtime_state.child_measurables(),
2189                kind,
2190            )
2191        };
2192        match runtime_state.take_child_error() {
2193            Some(err) => Err(err),
2194            None => Ok(Some(value)),
2195        }
2196    }
2197
2198    /// The measurement of a node whose own inputs did not change since it
2199    /// measured at `constraints`: only nodes below it are dirty.
2200    fn measurement_to_keep(
2201        &self,
2202        node: &LayoutNode,
2203        constraints: Constraints,
2204    ) -> Option<Rc<MeasuredNode>> {
2205        if node.needs_measure() || node.needs_layout() || node.is_virtual() {
2206            return None;
2207        }
2208        let cache = node.cache_handles();
2209        if cache.epoch() < self.cache_floor {
2210            return None;
2211        }
2212        cache.get_measurement(constraints)
2213    }
2214
2215    /// Measures again the children of `node_id` that changed, at the
2216    /// constraints they last had, and keeps the node's measurement when each
2217    /// of them measures the same for its parent: the node's policy would
2218    /// place them as before. `None` when one of them changed, and the node
2219    /// has to measure again.
2220    fn keep_measurement(
2221        self: &Rc<Self>,
2222        constraints: Constraints,
2223        node: KeptNode,
2224    ) -> Result<Option<Rc<MeasuredNode>>, NodeError> {
2225        let KeptNode {
2226            measured,
2227            runtime_state,
2228            cache,
2229            ignores_child_sizes,
2230        } = node;
2231        let mut next_state = 0;
2232        let kept = self.remeasure_changed_children(
2233            &measured,
2234            ignores_child_sizes,
2235            |child_id| self.layout_child_change(&runtime_state, &mut next_state, child_id),
2236            |_| {},
2237        )?;
2238        let Some(KeptChildren {
2239            measured: kept,
2240            resized,
2241        }) = kept
2242        else {
2243            return Ok(None);
2244        };
2245        if resized {
2246            cache.store_resized_measurement(constraints, Rc::clone(&kept));
2247        } else {
2248            cache.store_measurement(constraints, Rc::clone(&kept));
2249        }
2250        cache.clear_layout_dirt();
2251        Ok(Some(kept))
2252    }
2253
2254    /// Walks the children of a kept measurement, measures again each one
2255    /// `change` finds changed, at the constraints it last had, and keeps the
2256    /// measurement when each of them reads the same for it, or, when the
2257    /// measurement `ignores_child_sizes`, the same but for its size. `None`
2258    /// as soon as `change` refuses a child or one measures differently for
2259    /// its parent.
2260    fn remeasure_changed_children(
2261        self: &Rc<Self>,
2262        cached: &Rc<MeasuredNode>,
2263        ignores_child_sizes: bool,
2264        mut change: impl FnMut(NodeId) -> Result<ChildChange, NodeError>,
2265        mut remeasured: impl FnMut(NodeId),
2266    ) -> Result<Option<KeptChildren>, NodeError> {
2267        let mut resized = false;
2268        for previous in &cached.children {
2269            let child = match change(previous.node_id)? {
2270                ChildChange::Unchanged => continue,
2271                ChildChange::Refuse => return Ok(None),
2272                ChildChange::Changed(child) => child,
2273            };
2274            let measured = self.measure_node(previous.node_id, child.constraints)?;
2275            remeasured(previous.node_id);
2276            let now = ForParent::of(&measured);
2277            if !previous.for_parent.same_as(&now) {
2278                if !(ignores_child_sizes && previous.for_parent.same_but_size(&now)) {
2279                    return Ok(None);
2280                }
2281                resized = true;
2282            }
2283            if child.placed {
2284                self.place_where_it_was(cached.node_id, previous.node_id);
2285            }
2286        }
2287        Ok(Some(KeptChildren {
2288            measured: Rc::clone(cached),
2289            resized,
2290        }))
2291    }
2292
2293    /// What the walk over a kept layout node finds of a child, from the
2294    /// record of the node's last measure, which `next_state` walks in order.
2295    /// A changed child refuses the keep when its parent data changed, the
2296    /// node read its intrinsic sizes, or the node did not measure it.
2297    fn layout_child_change(
2298        &self,
2299        runtime_state: &RefCell<LayoutRuntimeState>,
2300        next_state: &mut usize,
2301        child_id: NodeId,
2302    ) -> Result<ChildChange, NodeError> {
2303        let runtime_state = runtime_state.borrow();
2304        let Some((offset, state)) = runtime_state
2305            .child_states()
2306            .get(*next_state..)
2307            .unwrap_or_default()
2308            .iter()
2309            .enumerate()
2310            .find(|(_, state)| state.node_id == child_id)
2311        else {
2312            return Ok(ChildChange::Refuse);
2313        };
2314        *next_state += offset + 1;
2315        // A clean child's flags sit in the cache its record shares with it.
2316        if read_cell(&state.cache, |cache| {
2317            cache.as_ref().is_some_and(|cache| !cache.dirt().any())
2318        }) {
2319            return Ok(ChildChange::Unchanged);
2320        }
2321        self.child_change(child_id, |view| {
2322            let parent_data_changed = view.parent_data.as_ref().is_some_and(|data| {
2323                read_cell(&state.parent_data, |bound| {
2324                    bound.as_ref().is_none_or(|bound| {
2325                        runtime_state
2326                            .measure_policy
2327                            .reads_parent_data_change(bound, data)
2328                    })
2329                })
2330            });
2331            match state.measured_constraints.get() {
2332                Some(constraints) if !state.read_intrinsics.get() && !parent_data_changed => {
2333                    ChildChange::Changed(ChangedChild {
2334                        constraints,
2335                        placed: view.placed,
2336                    })
2337                }
2338                _ => ChildChange::Refuse,
2339            }
2340        })
2341    }
2342
2343    /// Stores a subcompose node's new measurement in its cache, as a layout
2344    /// node's measure stores its own.
2345    fn store_subcompose_measurement(
2346        &self,
2347        node_id: NodeId,
2348        constraints: Constraints,
2349        measured: &Rc<MeasuredNode>,
2350    ) {
2351        let Ok(mut applier) = self.applier.try_borrow_typed() else {
2352            return;
2353        };
2354        let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
2355            node.cache_handles()
2356                .store_measurement(constraints, Rc::clone(measured));
2357        });
2358    }
2359
2360    /// Places a child of the kept node `parent` where it was: the node's
2361    /// policy would place it there again.
2362    fn place_where_it_was(&self, parent: NodeId, child_id: NodeId) {
2363        let Ok(mut applier) = self.applier.try_borrow_typed() else {
2364            return;
2365        };
2366        if applier
2367            .with_node::<LayoutNode, _>(child_id, |child| {
2368                child.set_position(child.position(), Some(parent), &self.context);
2369            })
2370            .is_err()
2371        {
2372            let _ = applier.with_node::<SubcomposeLayoutNode, _>(child_id, |child| {
2373                child.set_position(child.layout_state().position(), Some(parent), &self.context);
2374            });
2375        }
2376    }
2377
2378    fn visit_layout_node(
2379        &self,
2380        node: &mut LayoutNode,
2381        constraints: Constraints,
2382        keep: bool,
2383    ) -> LayoutNodeVisit<'_> {
2384        node.clear_placed(&self.context);
2385        if keep && let Some(measured) = self.measurement_to_keep(node, constraints) {
2386            let cache = node.cache_handles();
2387            return LayoutNodeVisit::Keep(KeptNode {
2388                ignores_child_sizes: cache.ignores_child_sizes_of(&measured),
2389                measured,
2390                runtime_state: node.layout_runtime_state_handle(),
2391                cache: cache.clone(),
2392            });
2393        }
2394        let cache = node.cache_handles();
2395        cache.activate(self.cache_epoch);
2396        if !Node::layout_dirty(node)
2397            && let Some(cached) = cache.get_measurement(constraints)
2398        {
2399            node.clear_needs_measure();
2400            node.clear_needs_layout();
2401            return LayoutNodeVisit::Cached(cached);
2402        }
2403
2404        let spare = MeasuredSpare::take(cache);
2405        let runtime_state = node.layout_runtime_state_handle();
2406        let chain = runtime_state.borrow_mut().bind_node(node);
2407        let mut pools = VecPools::acquire(&self.frame_arena);
2408        pools.child_ids.extend_from_slice(&node.children);
2409        LayoutNodeVisit::Measure(LayoutNodeMeasure {
2410            runtime_state,
2411            chain,
2412            pools,
2413            spare,
2414        })
2415    }
2416
2417    fn bind_layout_children(
2418        self: &Rc<Self>,
2419        applier: &mut MemoryApplier,
2420        (node_id, runtime_state): (NodeId, &RefCell<LayoutRuntimeState>),
2421        child_ids: &[NodeId],
2422        pass: ChildPass,
2423    ) -> Result<(), NodeError> {
2424        let mut runtime_state = runtime_state.borrow_mut();
2425        runtime_state.bind_children(self, node_id, pass, child_ids.len());
2426        let mut bound = 0;
2427        for &child_id in child_ids {
2428            if self.bind_layout_child(applier, &mut runtime_state, bound, child_id)? {
2429                bound += 1;
2430            }
2431        }
2432        runtime_state.truncate_children(bound);
2433        Ok(())
2434    }
2435
2436    fn bind_layout_child(
2437        &self,
2438        applier: &mut MemoryApplier,
2439        runtime_state: &mut LayoutRuntimeState,
2440        position: usize,
2441        child_id: NodeId,
2442    ) -> Result<bool, NodeError> {
2443        let bound = applier.with_node::<LayoutNode, _>(child_id, |child| {
2444            runtime_state.child_state_at(position, child_id).bind(
2445                LayoutChildBinding {
2446                    cache: child.cache_handles(),
2447                    layout_state: Some(child.layout_state_handle()),
2448                    parent_data: Some(child.parent_data()),
2449                    dirty: child.needs_layout() || child.needs_measure(),
2450                    descendant_dirty: Node::descendant_needs_layout(child),
2451                },
2452                self,
2453            );
2454        });
2455        match bound {
2456            Ok(()) => Ok(true),
2457            Err(NodeError::TypeMismatch { .. }) => {
2458                match applier.with_node::<SubcomposeLayoutNode, _>(child_id, |child| {
2459                    runtime_state.child_state_at(position, child_id).bind(
2460                        LayoutChildBinding {
2461                            cache: child.cache_handles(),
2462                            layout_state: None,
2463                            parent_data: Some(child.parent_data()),
2464                            dirty: child.needs_layout() || child.needs_measure(),
2465                            descendant_dirty: Node::descendant_needs_layout(child),
2466                        },
2467                        self,
2468                    );
2469                }) {
2470                    Ok(()) => Ok(true),
2471                    Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => Ok(false),
2472                    Err(err) => Err(err),
2473                }
2474            }
2475            Err(NodeError::Missing { .. }) => Ok(false),
2476            Err(err) => Err(err),
2477        }
2478    }
2479
2480    fn measure_through_modifier_chain(
2481        &self,
2482        node_id: NodeId,
2483        runtime_state: &LayoutRuntimeState,
2484        chain: ModifierChainInputs,
2485        constraints: Constraints,
2486        placements: &mut Vec<Placement>,
2487        placement_indices: &mut Vec<usize>,
2488    ) -> ModifierChainMeasurement {
2489        let scope = crate::density::DensityMeasureScope::new(chain.density);
2490
2491        if !chain.uses_chain {
2492            let measurement = runtime_state.measure_policy.measure_into(
2493                &scope,
2494                runtime_state.child_measurables(),
2495                constraints,
2496                placements,
2497            );
2498            return ModifierChainMeasurement {
2499                size: measurement.size,
2500                alignment_lines: inherited_alignment_lines(
2501                    runtime_state.child_states(),
2502                    placements,
2503                    placement_indices,
2504                )
2505                .with_overrides(measurement.alignment_lines),
2506                content_offset: Point::default(),
2507                offset: chain.offset,
2508                window_root: chain.window_root,
2509                uses_chain: false,
2510                hold: if chain.window_root {
2511                    None
2512                } else {
2513                    runtime_state.measure_policy.measure_hold(
2514                        runtime_state.child_measurables(),
2515                        constraints,
2516                        measurement.size,
2517                    )
2518                },
2519                ignores_child_sizes: !chain.window_root
2520                    && runtime_state
2521                        .measure_policy
2522                        .ignores_child_sizes(runtime_state.child_measurables(), constraints),
2523            };
2524        }
2525
2526        let frame = CoordinatorFrame::new(
2527            &runtime_state.measure_policy,
2528            &scope,
2529            runtime_state.child_measurables(),
2530            runtime_state.child_states(),
2531            placements,
2532            placement_indices,
2533        );
2534        let placeable = runtime_state
2535            .coordinator_chain
2536            .measure_from(0, &frame, constraints);
2537        let (content_x, content_y) = placeable.content_offset();
2538
2539        let invalidations = frame.take_invalidations();
2540        if !invalidations.is_empty() {
2541            self.with_applier_result(|applier| {
2542                applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
2543                    for kind in invalidations {
2544                        match kind {
2545                            InvalidationKind::Layout => layout_node.mark_needs_measure(),
2546                            InvalidationKind::Draw => layout_node.mark_needs_redraw(),
2547                            InvalidationKind::Semantics => layout_node.mark_needs_semantics(),
2548                            InvalidationKind::PointerInput => layout_node.mark_needs_pointer_pass(),
2549                            InvalidationKind::Focus => layout_node.mark_needs_focus_sync(),
2550                        }
2551                    }
2552                })
2553            })
2554            .ok();
2555        }
2556
2557        ModifierChainMeasurement {
2558            alignment_lines: placeable.alignment_lines(),
2559            size: Size {
2560                width: placeable.width(),
2561                height: placeable.height(),
2562            },
2563            content_offset: Point {
2564                x: content_x - chain.offset.x,
2565                y: content_y - chain.offset.y,
2566            },
2567            offset: chain.offset,
2568            window_root: chain.window_root,
2569            uses_chain: true,
2570            hold: if chain.window_root {
2571                None
2572            } else {
2573                runtime_state.coordinator_chain.measured_hold(
2574                    cranpose_ui_layout::MeasureScope::density(&scope),
2575                    runtime_state.measure_policy.as_ref(),
2576                    runtime_state.child_measurables(),
2577                )
2578            },
2579            ignores_child_sizes: !chain.window_root
2580                && runtime_state.coordinator_chain.ignores_child_sizes(
2581                    runtime_state.measure_policy.as_ref(),
2582                    runtime_state.child_measurables(),
2583                ),
2584        }
2585    }
2586}
2587
2588struct VecPools<'a> {
2589    arena: &'a RefCell<FrameLayoutArena>,
2590    child_ids: Vec<NodeId>,
2591    placements: Vec<Placement>,
2592}
2593
2594impl<'a> VecPools<'a> {
2595    fn acquire(arena: &'a RefCell<FrameLayoutArena>) -> Self {
2596        let mut pools = arena.borrow_mut();
2597        let child_ids = pools.tmp_child_ids.acquire();
2598        let placements = pools.tmp_placements.acquire();
2599        Self {
2600            arena,
2601            child_ids,
2602            placements,
2603        }
2604    }
2605}
2606
2607impl Drop for VecPools<'_> {
2608    fn drop(&mut self) {
2609        let mut pools = self.arena.borrow_mut();
2610        pools
2611            .tmp_child_ids
2612            .release(std::mem::take(&mut self.child_ids));
2613        pools
2614            .tmp_placements
2615            .release(std::mem::take(&mut self.placements));
2616    }
2617}
2618
2619/// The measurement of each placement a lazy policy made, in order: see
2620/// [`crate::subcompose_layout::SubcomposeMeasureScopeImpl::layout_with_placed_roots`].
2621struct PlacedRootMeasurements<'a> {
2622    items: std::slice::Iter<'a, Rc<LazyItemRoots>>,
2623    /// The measurements of the item being placed, one a root; empty for an
2624    /// item that holds none.
2625    measured: &'a [Rc<MeasuredNode>],
2626    /// The item's next root, and how many roots it has.
2627    root: usize,
2628    roots: usize,
2629}
2630
2631impl<'a> PlacedRootMeasurements<'a> {
2632    fn new(items: &'a [Rc<LazyItemRoots>]) -> Self {
2633        Self {
2634            items: items.iter(),
2635            measured: &[],
2636            root: 0,
2637            roots: 0,
2638        }
2639    }
2640
2641    /// The measurement of the next placement; `None` for a root the item
2642    /// holds none for, and once every item is placed.
2643    fn next_measurement(&mut self) -> Option<&'a MeasuredNode> {
2644        while self.root == self.roots {
2645            let item = self.items.next()?;
2646            self.measured = crate::widgets::lazy_list::root_measurements(item)
2647                .map_or(&[], smallvec::SmallVec::as_slice);
2648            self.root = 0;
2649            self.roots = item.node_ids.len();
2650        }
2651        let measured = self.measured.get(self.root);
2652        self.root += 1;
2653        measured.map(|measured| &**measured)
2654    }
2655}
2656
2657#[derive(Debug, Clone)]
2658pub(crate) struct MeasuredNode {
2659    node_id: NodeId,
2660    size: Size,
2661    offset: Point,
2662    content_offset: Point,
2663    alignment_lines: AlignmentLines,
2664    children: Vec<MeasuredChild>,
2665    window_root: bool,
2666}
2667
2668impl MeasuredNode {
2669    fn new(
2670        node_id: NodeId,
2671        size: Size,
2672        offset: Point,
2673        content_offset: Point,
2674        children: Vec<MeasuredChild>,
2675    ) -> Self {
2676        Self {
2677            node_id,
2678            size,
2679            offset,
2680            content_offset,
2681            alignment_lines: AlignmentLines::default(),
2682            children,
2683            window_root: false,
2684        }
2685    }
2686
2687    fn with_window_root(mut self, window_root: bool) -> Self {
2688        self.window_root = window_root;
2689        self
2690    }
2691
2692    fn with_alignment_lines(mut self, alignment_lines: AlignmentLines) -> Self {
2693        self.alignment_lines = alignment_lines;
2694        self
2695    }
2696
2697    pub(crate) fn alignment_lines_for_parent(&self) -> AlignmentLines {
2698        if self.window_root {
2699            AlignmentLines::default()
2700        } else {
2701            self.alignment_lines
2702        }
2703    }
2704
2705    pub(crate) fn size_for_parent(&self) -> Size {
2706        if self.window_root {
2707            Size::new(0.0, 0.0)
2708        } else {
2709            self.size
2710        }
2711    }
2712
2713    pub(crate) fn size(&self) -> Size {
2714        self.size
2715    }
2716
2717    /// The measurement in `spare`'s memory, or in a new allocation when
2718    /// there is no spare.
2719    fn into_rc(self, spare: Option<Rc<MeasuredNode>>) -> Rc<MeasuredNode> {
2720        let Some(mut spare) = spare else {
2721            return Rc::new(self);
2722        };
2723        match Rc::get_mut(&mut spare) {
2724            Some(slot) => *slot = self,
2725            None => return Rc::new(self),
2726        }
2727        spare
2728    }
2729}
2730
2731/// The memory of a node's last measurement, children's list included, for
2732/// its next measure to fill. It is taken only when nothing else holds the
2733/// measurement.
2734#[derive(Default)]
2735struct MeasuredSpare {
2736    node: Option<Rc<MeasuredNode>>,
2737    children: Vec<MeasuredChild>,
2738}
2739
2740impl MeasuredSpare {
2741    fn take(cache: &LayoutNodeCacheHandles) -> Self {
2742        let Some(mut node) = cache.take_previous_measurement() else {
2743            return Self::default();
2744        };
2745        let Some(previous) = Rc::get_mut(&mut node) else {
2746            return Self::default();
2747        };
2748        let mut children = std::mem::take(&mut previous.children);
2749        children.clear();
2750        Self {
2751            node: Some(node),
2752            children,
2753        }
2754    }
2755}
2756
2757/// What a parent's measurement keeps of a child: which child, where the
2758/// policy placed it, and what of the child's measurement the policy read.
2759/// The measurement itself stays with the child's cache, its one holder, so
2760/// the child's next measure can fill it in place.
2761#[derive(Debug, Clone, Copy)]
2762struct MeasuredChild {
2763    node_id: NodeId,
2764    offset: Point,
2765    for_parent: ForParent,
2766}
2767
2768impl MeasuredChild {
2769    fn new(measured: &MeasuredNode, offset: Point) -> Self {
2770        Self {
2771            node_id: measured.node_id,
2772            offset,
2773            for_parent: ForParent::of(measured),
2774        }
2775    }
2776}
2777
2778/// What a parent's policy reads of a child's measurement: the size and the
2779/// baselines, and the offset it places the child by.
2780#[derive(Debug, Clone, Copy)]
2781struct ForParent {
2782    size: Size,
2783    offset: Point,
2784    alignment_lines: AlignmentLines,
2785}
2786
2787impl ForParent {
2788    fn of(measured: &MeasuredNode) -> Self {
2789        Self {
2790            size: measured.size_for_parent(),
2791            offset: measured.offset,
2792            alignment_lines: measured.alignment_lines_for_parent(),
2793        }
2794    }
2795
2796    /// Whether a parent's policy, reading `other` in place of this, would
2797    /// lay its children out the same.
2798    fn same_as(&self, other: &Self) -> bool {
2799        self.size == other.size && self.same_but_size(other)
2800    }
2801
2802    /// Whether `other` reads the same as this but for its size.
2803    fn same_but_size(&self, other: &Self) -> bool {
2804        self.offset == other.offset
2805            && self.alignment_lines.first_baseline() == other.alignment_lines.first_baseline()
2806            && self.alignment_lines.last_baseline() == other.alignment_lines.last_baseline()
2807    }
2808}
2809
2810/// The intrinsic size `kind` names, of a measurable.
2811fn measurable_intrinsic(measurable: &dyn Measurable, kind: IntrinsicKind) -> f32 {
2812    match kind {
2813        IntrinsicKind::MinWidth(height) => measurable.min_intrinsic_width(height),
2814        IntrinsicKind::MaxWidth(height) => measurable.max_intrinsic_width(height),
2815        IntrinsicKind::MinHeight(width) => measurable.min_intrinsic_height(width),
2816        IntrinsicKind::MaxHeight(width) => measurable.max_intrinsic_height(width),
2817    }
2818}
2819
2820/// The intrinsic size `kind` names, of a measure policy over `measurables`.
2821fn policy_intrinsic(
2822    policy: &dyn MeasurePolicy,
2823    measurables: &[Box<dyn Measurable>],
2824    kind: IntrinsicKind,
2825) -> f32 {
2826    match kind {
2827        IntrinsicKind::MinWidth(height) => policy.min_intrinsic_width(measurables, height),
2828        IntrinsicKind::MaxWidth(height) => policy.max_intrinsic_width(measurables, height),
2829        IntrinsicKind::MinHeight(width) => policy.min_intrinsic_height(measurables, width),
2830        IntrinsicKind::MaxHeight(width) => policy.max_intrinsic_height(measurables, width),
2831    }
2832}
2833
2834/// The intrinsic size `kind` names, of a layout modifier around `wrapped`.
2835fn layout_modifier_intrinsic(
2836    node: &dyn cranpose_foundation::LayoutModifierNode,
2837    wrapped: &dyn Measurable,
2838    kind: IntrinsicKind,
2839    density: f32,
2840) -> f32 {
2841    match kind {
2842        IntrinsicKind::MinWidth(height) => node.min_intrinsic_width(wrapped, height, density),
2843        IntrinsicKind::MaxWidth(height) => node.max_intrinsic_width(wrapped, height, density),
2844        IntrinsicKind::MinHeight(width) => node.min_intrinsic_height(wrapped, width, density),
2845        IntrinsicKind::MaxHeight(width) => node.max_intrinsic_height(wrapped, width, density),
2846    }
2847}
2848
2849struct CoordinatorFrame<'a> {
2850    measure_policy: &'a Rc<dyn MeasurePolicy>,
2851    scope: &'a dyn cranpose_ui_layout::MeasureScope,
2852    measurables: &'a [Box<dyn Measurable>],
2853    child_states: &'a [Rc<LayoutChildMeasureState>],
2854    placements: RefCell<&'a mut Vec<Placement>>,
2855    placement_indices: RefCell<&'a mut Vec<usize>>,
2856    context: RefCell<LayoutNodeContext>,
2857}
2858
2859impl<'a> CoordinatorFrame<'a> {
2860    fn new(
2861        measure_policy: &'a Rc<dyn MeasurePolicy>,
2862        scope: &'a dyn cranpose_ui_layout::MeasureScope,
2863        measurables: &'a [Box<dyn Measurable>],
2864        child_states: &'a [Rc<LayoutChildMeasureState>],
2865        placements: &'a mut Vec<Placement>,
2866        placement_indices: &'a mut Vec<usize>,
2867    ) -> Self {
2868        Self {
2869            measure_policy,
2870            scope,
2871            measurables,
2872            child_states,
2873            placements: RefCell::new(placements),
2874            placement_indices: RefCell::new(placement_indices),
2875            context: RefCell::new(LayoutNodeContext::new(scope.density())),
2876        }
2877    }
2878
2879    fn take_invalidations(&self) -> Vec<InvalidationKind> {
2880        self.context.borrow_mut().take_invalidations()
2881    }
2882}
2883
2884struct CoordinatorLink<'chain, 'frame_ref, 'frame_data> {
2885    chain: &'chain CoordinatorChain,
2886    frame: &'frame_ref CoordinatorFrame<'frame_data>,
2887    index: usize,
2888    alignment_lines: Cell<AlignmentLines>,
2889}
2890
2891impl<'chain, 'frame_ref, 'frame_data> CoordinatorLink<'chain, 'frame_ref, 'frame_data> {
2892    fn new(
2893        chain: &'chain CoordinatorChain,
2894        frame: &'frame_ref CoordinatorFrame<'frame_data>,
2895        index: usize,
2896    ) -> Self {
2897        Self {
2898            chain,
2899            frame,
2900            index,
2901            alignment_lines: Cell::default(),
2902        }
2903    }
2904}
2905
2906impl Measurable for CoordinatorLink<'_, '_, '_> {
2907    fn measure(&self, constraints: Constraints) -> Placeable {
2908        let placeable = self.chain.measure_from(self.index, self.frame, constraints);
2909        self.alignment_lines.set(placeable.alignment_lines());
2910        placeable
2911    }
2912
2913    fn min_intrinsic_width(&self, height: f32) -> f32 {
2914        self.chain
2915            .intrinsic_from(self.index, self.frame, IntrinsicKind::MinWidth(height))
2916    }
2917
2918    fn max_intrinsic_width(&self, height: f32) -> f32 {
2919        self.chain
2920            .intrinsic_from(self.index, self.frame, IntrinsicKind::MaxWidth(height))
2921    }
2922
2923    fn min_intrinsic_height(&self, width: f32) -> f32 {
2924        self.chain
2925            .intrinsic_from(self.index, self.frame, IntrinsicKind::MinHeight(width))
2926    }
2927
2928    fn max_intrinsic_height(&self, width: f32) -> f32 {
2929        self.chain
2930            .intrinsic_from(self.index, self.frame, IntrinsicKind::MaxHeight(width))
2931    }
2932}
2933
2934struct CoordinatorNode {
2935    modifier_index: usize,
2936    node: Rc<RefCell<dyn cranpose_foundation::ModifierNode>>,
2937    measured_size: Cell<Size>,
2938    /// The constraints this node last measured under.
2939    measured_constraints: Cell<Constraints>,
2940    accumulated_offset: Cell<Point>,
2941}
2942
2943impl CoordinatorNode {
2944    fn new(
2945        modifier_index: usize,
2946        node: Rc<RefCell<dyn cranpose_foundation::ModifierNode>>,
2947    ) -> Self {
2948        Self {
2949            modifier_index,
2950            node,
2951            measured_size: Cell::new(Size::default()),
2952            measured_constraints: Cell::new(Constraints::tight(0.0, 0.0)),
2953            accumulated_offset: Cell::new(Point::default()),
2954        }
2955    }
2956
2957    fn matches(
2958        &self,
2959        modifier_index: usize,
2960        node: &Rc<RefCell<dyn cranpose_foundation::ModifierNode>>,
2961    ) -> bool {
2962        self.modifier_index == modifier_index && Rc::ptr_eq(&self.node, node)
2963    }
2964
2965    #[cfg(test)]
2966    fn ptr(&self) -> usize {
2967        Rc::as_ptr(&self.node) as *const () as usize
2968    }
2969}
2970
2971#[derive(Default)]
2972struct CoordinatorChain {
2973    nodes: Vec<CoordinatorNode>,
2974    /// The size the node's own measure policy measured its content at.
2975    inner_size: Cell<Size>,
2976    /// The constraints the node's own measure policy last measured under.
2977    inner_constraints: Cell<Option<Constraints>>,
2978    /// The chain revision the nodes were last synced at and the inputs it
2979    /// gave: a node whose modifiers did not change since measures again
2980    /// without walking its chain.
2981    synced: Option<(u64, ModifierChainInputs)>,
2982}
2983
2984impl CoordinatorChain {
2985    fn sync(&mut self, node: &LayoutNode) -> ModifierChainInputs {
2986        let density = node.density();
2987        let revision = node.modifier_chain().revision();
2988        if let Some((synced, inputs)) = self.synced
2989            && synced == revision
2990            && inputs.density == density
2991        {
2992            return inputs;
2993        }
2994        let inputs = self.walk(node, density);
2995        self.synced = Some((revision, inputs));
2996        inputs
2997    }
2998
2999    /// Syncs the nodes with the layout nodes of `node`'s chain and sums
3000    /// its offsets.
3001    fn walk(&mut self, node: &LayoutNode, density: crate::density::Density) -> ModifierChainInputs {
3002        let mut inputs = ModifierChainInputs {
3003            density,
3004            window_root: node.is_window_root(),
3005            offset: Point::default(),
3006            uses_chain: false,
3007        };
3008        let chain_handle = node.modifier_chain();
3009        if !chain_handle.has_layout_nodes() {
3010            return inputs;
3011        }
3012
3013        let chain = chain_handle.chain();
3014        let mut len = 0;
3015        let mut matches = true;
3016        chain.for_each_forward_matching(NodeCapabilities::LAYOUT, |node_ref| {
3017            let Some(index) = node_ref.entry_index() else {
3018                return;
3019            };
3020            if let Some(node) = chain.get_node_rc(index) {
3021                matches = matches
3022                    && self
3023                        .nodes
3024                        .get(len)
3025                        .is_some_and(|candidate| candidate.matches(index, node));
3026                len += 1;
3027            }
3028            node_ref.with_node(|node| {
3029                if let Some(offset_node) = node
3030                    .as_any()
3031                    .downcast_ref::<crate::modifier_nodes::OffsetNode>()
3032                {
3033                    let delta = offset_node.device_offset(density.density());
3034                    inputs.offset.x += delta.x;
3035                    inputs.offset.y += delta.y;
3036                }
3037            });
3038        });
3039
3040        inputs.uses_chain = len > 0;
3041        if inputs.uses_chain && !(matches && len == self.nodes.len()) {
3042            self.rebuild(chain, len);
3043        }
3044        inputs
3045    }
3046
3047    fn rebuild(&mut self, chain: &cranpose_foundation::ModifierNodeChain, len: usize) {
3048        let mut previous_nodes = std::mem::take(&mut self.nodes);
3049        // Exactly: most chains hold one layout modifier, where growth would
3050        // make room for four.
3051        self.nodes.reserve_exact(len);
3052        chain.for_each_forward_matching(NodeCapabilities::LAYOUT, |node_ref| {
3053            let Some((index, node)) = node_ref
3054                .entry_index()
3055                .and_then(|index| chain.get_node_rc(index).map(|node| (index, node)))
3056            else {
3057                return;
3058            };
3059            match previous_nodes
3060                .iter()
3061                .position(|candidate| candidate.matches(index, node))
3062            {
3063                Some(position) => self.nodes.push(previous_nodes.swap_remove(position)),
3064                None => self
3065                    .nodes
3066                    .push(CoordinatorNode::new(index, Rc::clone(node))),
3067            }
3068        });
3069    }
3070
3071    /// What the last measure through this chain holds for: the policy's own
3072    /// range, then each layout modifier from the innermost out turns its
3073    /// content's range into its own; any other node passes its constraints
3074    /// through.
3075    fn measured_hold(
3076        &self,
3077        density: f32,
3078        policy: &dyn MeasurePolicy,
3079        measurables: &[Box<dyn Measurable>],
3080    ) -> Option<cranpose_ui_layout::ConstraintsHold> {
3081        let inner_size = self.inner_size.get();
3082        let mut wrapped = cranpose_ui_layout::WrappedHold {
3083            size: inner_size,
3084            hold: self
3085                .inner_constraints
3086                .get()
3087                .and_then(|constraints| policy.measure_hold(measurables, constraints, inner_size)),
3088        };
3089        for node in self.nodes.iter().rev() {
3090            let size = node.measured_size.get();
3091            let hold = match node.node.borrow().as_layout_node() {
3092                Some(layout) => {
3093                    layout.measure_hold(density, node.measured_constraints.get(), size, wrapped)
3094                }
3095                None => wrapped.hold,
3096            };
3097            wrapped = cranpose_ui_layout::WrappedHold { size, hold };
3098        }
3099        wrapped.hold
3100    }
3101
3102    /// Whether the policy's last measure through this chain ignored its
3103    /// children's sizes. The layout modifiers around it see only its size,
3104    /// which then stays as it is.
3105    fn ignores_child_sizes(
3106        &self,
3107        policy: &dyn MeasurePolicy,
3108        measurables: &[Box<dyn Measurable>],
3109    ) -> bool {
3110        self.inner_constraints
3111            .get()
3112            .is_some_and(|constraints| policy.ignores_child_sizes(measurables, constraints))
3113    }
3114
3115    fn measure_from(
3116        &self,
3117        index: usize,
3118        frame: &CoordinatorFrame<'_>,
3119        constraints: Constraints,
3120    ) -> Placeable {
3121        let Some(node) = self.nodes.get(index) else {
3122            let mut placements = frame.placements.borrow_mut();
3123            let measurement = frame.measure_policy.measure_into(
3124                frame.scope,
3125                frame.measurables,
3126                constraints,
3127                &mut placements,
3128            );
3129            self.inner_size.set(measurement.size);
3130            self.inner_constraints.set(Some(constraints));
3131            return Placeable::value(
3132                measurement.size.width,
3133                measurement.size.height,
3134                NodeId::default(),
3135            )
3136            .with_alignment_lines(
3137                inherited_alignment_lines(
3138                    frame.child_states,
3139                    &placements,
3140                    &mut frame.placement_indices.borrow_mut(),
3141                )
3142                .with_overrides(measurement.alignment_lines),
3143            );
3144        };
3145
3146        let wrapped = CoordinatorLink::new(self, frame, index + 1);
3147        let node_borrow = node.node.borrow();
3148        node.measured_constraints.set(constraints);
3149
3150        let Some(layout_node) = node_borrow.as_layout_node() else {
3151            let placeable = wrapped.measure(constraints);
3152            node.measured_size.set(Size {
3153                width: placeable.width(),
3154                height: placeable.height(),
3155            });
3156            let child_accumulated = self.total_content_offset_from(index + 1);
3157            node.accumulated_offset.set(child_accumulated);
3158            return placeable;
3159        };
3160
3161        let result = match frame.context.try_borrow_mut() {
3162            Ok(mut context) => layout_node.measure(&mut *context, &wrapped, constraints),
3163            Err(_) => {
3164                let mut temp = LayoutNodeContext::new(frame.scope.density());
3165                let result = layout_node.measure(&mut temp, &wrapped, constraints);
3166                if let Ok(mut context) = frame.context.try_borrow_mut() {
3167                    for kind in temp.take_invalidations() {
3168                        context.invalidate(kind);
3169                    }
3170                }
3171                result
3172            }
3173        };
3174
3175        node.measured_size.set(result.size);
3176        let local_offset = Point {
3177            x: result.placement_offset_x,
3178            y: result.placement_offset_y,
3179        };
3180        let child_accumulated = self.total_content_offset_from(index + 1);
3181        let accumulated = Point {
3182            x: local_offset.x + child_accumulated.x,
3183            y: local_offset.y + child_accumulated.y,
3184        };
3185        node.accumulated_offset.set(accumulated);
3186
3187        Placeable::value_with_offset(
3188            result.size.width,
3189            result.size.height,
3190            NodeId::default(),
3191            (accumulated.x, accumulated.y),
3192        )
3193        .with_alignment_lines(
3194            wrapped
3195                .alignment_lines
3196                .get()
3197                .translated(local_offset.y)
3198                .with_overrides(result.alignment_lines),
3199        )
3200    }
3201
3202    fn intrinsic_from(
3203        &self,
3204        index: usize,
3205        frame: &CoordinatorFrame<'_>,
3206        kind: IntrinsicKind,
3207    ) -> f32 {
3208        let Some(node) = self.nodes.get(index) else {
3209            return policy_intrinsic(frame.measure_policy.as_ref(), frame.measurables, kind);
3210        };
3211        let wrapped = CoordinatorLink::new(self, frame, index + 1);
3212        let node_borrow = node.node.borrow();
3213        node_borrow.as_layout_node().map_or_else(
3214            || measurable_intrinsic(&wrapped, kind),
3215            |layout_node| {
3216                layout_modifier_intrinsic(layout_node, &wrapped, kind, frame.scope.density())
3217            },
3218        )
3219    }
3220
3221    /// Writes where each coordinator and the node's content ended up in the
3222    /// last measure, relative to the node drawn at its `node_offset`, and
3223    /// says whether any of them moved.
3224    fn write_geometry(
3225        &self,
3226        geometry: &crate::modifier::CoordinatorGeometry,
3227        node_offset: Point,
3228    ) -> bool {
3229        let content = self.total_content_offset_from(0);
3230        let placed = |inner_offset: Point, size: Size| GeometryRect {
3231            x: content.x - inner_offset.x - node_offset.x,
3232            y: content.y - inner_offset.y - node_offset.y,
3233            width: size.width,
3234            height: size.height,
3235        };
3236        geometry.replace(
3237            self.nodes
3238                .iter()
3239                .map(|node| placed(node.accumulated_offset.get(), node.measured_size.get()))
3240                .chain(std::iter::once(placed(
3241                    Point::default(),
3242                    self.inner_size.get(),
3243                ))),
3244        )
3245    }
3246
3247    fn total_content_offset_from(&self, index: usize) -> Point {
3248        self.nodes
3249            .get(index)
3250            .map(|node| node.accumulated_offset.get())
3251            .unwrap_or_default()
3252    }
3253
3254    #[cfg(test)]
3255    fn debug_ptrs(&self) -> Vec<usize> {
3256        self.nodes.iter().map(CoordinatorNode::ptr).collect()
3257    }
3258}
3259
3260fn inherited_alignment_lines(
3261    child_states: &[Rc<LayoutChildMeasureState>],
3262    placements: &[Placement],
3263    placement_indices: &mut Vec<usize>,
3264) -> AlignmentLines {
3265    placement_indices.clear();
3266    let in_child_order = placements.len() == child_states.len()
3267        && placements
3268            .iter()
3269            .zip(child_states)
3270            .all(|(placement, child)| placement.node_id == child.node_id);
3271    if !in_child_order {
3272        placement_indices.extend(0..placements.len());
3273        placement_indices.sort_unstable_by_key(|&index| (placements[index].node_id, index));
3274    }
3275    let mut lines = AlignmentLines::default();
3276    for (index, child) in child_states.iter().enumerate() {
3277        let placement = placement_for_child(placements, placement_indices, index, child.node_id);
3278        read_cell(&child.measured, |measured| {
3279            if let Some(measured) = measured {
3280                lines.merge(
3281                    measured
3282                        .alignment_lines_for_parent()
3283                        .translated(child.placement_position(placement).y),
3284                );
3285            }
3286        });
3287    }
3288    lines
3289}
3290
3291fn placement_for_child<'a>(
3292    placements: &'a [Placement],
3293    indices: &[usize],
3294    child_index: usize,
3295    node_id: NodeId,
3296) -> Option<&'a Placement> {
3297    let index = if indices.is_empty() {
3298        child_index
3299    } else {
3300        let first = indices.partition_point(|&index| placements[index].node_id < node_id);
3301        *indices.get(first)?
3302    };
3303    placements
3304        .get(index)
3305        .filter(|placement| placement.node_id == node_id)
3306}
3307
3308pub(crate) struct LayoutRuntimeState {
3309    /// `None` until the node first binds a child: most nodes are leaves.
3310    children: Option<Box<LayoutChildren>>,
3311    coordinator_chain: CoordinatorChain,
3312    measure_policy: Rc<dyn MeasurePolicy>,
3313}
3314
3315/// What a node keeps for measuring its children, in their order.
3316struct LayoutChildren {
3317    ids: Vec<NodeId>,
3318    states: Vec<Rc<LayoutChildMeasureState>>,
3319    measurables: Vec<Box<dyn Measurable>>,
3320    frame: Rc<LayoutChildFrame>,
3321}
3322
3323impl LayoutChildren {
3324    /// Room for exactly `count` children, where growth would make room for
3325    /// four in each of the three lists. Children added later grow the lists
3326    /// as usual.
3327    fn with_capacity(count: usize) -> Self {
3328        Self {
3329            ids: Vec::with_capacity(count),
3330            states: Vec::with_capacity(count),
3331            measurables: Vec::with_capacity(count),
3332            frame: Rc::default(),
3333        }
3334    }
3335
3336    /// Puts the state of `child_id` at `position`: the one it had further
3337    /// on, or a new one.
3338    #[inline(never)]
3339    fn bind_at(&mut self, position: usize, child_id: NodeId) {
3340        let from = match self.ids[position..].iter().position(|&id| id == child_id) {
3341            Some(offset) => position + offset,
3342            None => {
3343                let state = LayoutChildMeasureState::new(child_id, Rc::clone(&self.frame));
3344                self.ids.push(child_id);
3345                self.states.push(Rc::clone(&state));
3346                self.measurables
3347                    .push(Box::new(LayoutChildMeasurable::new(state)));
3348                self.ids.len() - 1
3349            }
3350        };
3351        self.ids.swap(position, from);
3352        self.states.swap(position, from);
3353        self.measurables.swap(position, from);
3354    }
3355}
3356
3357impl LayoutRuntimeState {
3358    pub(crate) fn new(measure_policy: Rc<dyn MeasurePolicy>) -> Self {
3359        Self {
3360            children: None,
3361            coordinator_chain: CoordinatorChain::default(),
3362            measure_policy,
3363        }
3364    }
3365
3366    fn bind_node(&mut self, node: &LayoutNode) -> ModifierChainInputs {
3367        if !Rc::ptr_eq(&self.measure_policy, &node.measure_policy) {
3368            self.measure_policy = Rc::clone(&node.measure_policy);
3369        }
3370        self.coordinator_chain.sync(node)
3371    }
3372
3373    fn child_states(&self) -> &[Rc<LayoutChildMeasureState>] {
3374        self.children
3375            .as_deref()
3376            .map_or(&[], |children| children.states.as_slice())
3377    }
3378
3379    fn child_measurables(&self) -> &[Box<dyn Measurable>] {
3380        self.children
3381            .as_deref()
3382            .map_or(&[], |children| children.measurables.as_slice())
3383    }
3384
3385    /// Binds the children's frame of the node `parent` to `builder` for a
3386    /// pass over `count` children. A node that never had one binds nothing.
3387    fn bind_children(
3388        &mut self,
3389        builder: &Rc<LayoutBuilderState>,
3390        parent: NodeId,
3391        pass: ChildPass,
3392        count: usize,
3393    ) {
3394        if count == 0 && self.children.is_none() {
3395            return;
3396        }
3397        self.children
3398            .get_or_insert_with(|| Box::new(LayoutChildren::with_capacity(count)))
3399            .frame
3400            .bind(builder, parent, pass);
3401    }
3402
3403    fn unbind_children(&self) {
3404        if let Some(children) = &self.children {
3405            children.frame.unbind();
3406        }
3407    }
3408
3409    /// The first error a child recorded in the pass, taken.
3410    fn take_child_error(&self) -> Option<NodeError> {
3411        self.children
3412            .as_ref()
3413            .and_then(|children| children.frame.error.borrow_mut().take())
3414    }
3415
3416    /// The state of the child at `position`, for a pass `bind_children`
3417    /// bound. Inlined: the child is nearly always where it was.
3418    #[inline]
3419    fn child_state_at(&mut self, position: usize, child_id: NodeId) -> &LayoutChildMeasureState {
3420        let children = self
3421            .children
3422            .get_or_insert_with(|| Box::new(LayoutChildren::with_capacity(position + 1)));
3423        if children.ids.get(position) != Some(&child_id) {
3424            children.bind_at(position, child_id);
3425        }
3426        &children.states[position]
3427    }
3428
3429    fn truncate_children(&mut self, len: usize) {
3430        if let Some(children) = &mut self.children {
3431            children.ids.truncate(len);
3432            children.states.truncate(len);
3433            children.measurables.truncate(len);
3434        }
3435    }
3436
3437    /// Puts the children the last measure measured into `measured_children`.
3438    fn measured_children(
3439        &self,
3440        placements: &[Placement],
3441        placement_indices: &[usize],
3442        content_offset: Point,
3443        measured_children: &mut Vec<MeasuredChild>,
3444    ) {
3445        let child_states = self.child_states();
3446        measured_children.reserve_exact(child_states.len());
3447        for (index, child_state) in child_states.iter().enumerate() {
3448            let Some(measured) = child_state.measured.take() else {
3449                continue;
3450            };
3451            let placement =
3452                placement_for_child(placements, placement_indices, index, child_state.node_id);
3453            let base_position = child_state.placement_position(placement);
3454            let position = Point {
3455                x: base_position.x + measured.offset.x,
3456                y: base_position.y + measured.offset.y,
3457            };
3458            // A policy that placed the child there in this pass, as one
3459            // that places its placeables does, left nothing to place.
3460            if placement.is_some() && child_state.last_position.get() != Some(position) {
3461                child_state.place_retained(position);
3462            }
3463            measured_children.push(MeasuredChild::new(
3464                &measured,
3465                Point {
3466                    x: content_offset.x + base_position.x,
3467                    y: content_offset.y + base_position.y,
3468                },
3469            ));
3470        }
3471    }
3472
3473    /// Writes the node's coordinator geometry and returns whether it moved.
3474    fn write_node_geometry(
3475        &self,
3476        node: &LayoutNode,
3477        measurement: &ModifierChainMeasurement,
3478    ) -> bool {
3479        let geometry = node.coordinator_geometry();
3480        if measurement.uses_chain {
3481            self.coordinator_chain
3482                .write_geometry(geometry, measurement.offset)
3483        } else {
3484            geometry.replace([GeometryRect {
3485                x: 0.0,
3486                y: 0.0,
3487                width: measurement.size.width,
3488                height: measurement.size.height,
3489            }])
3490        }
3491    }
3492
3493    #[cfg(test)]
3494    pub(crate) fn debug_stats(&self) -> LayoutRuntimeDebugStats {
3495        LayoutRuntimeDebugStats {
3496            child_ids: self
3497                .children
3498                .as_ref()
3499                .map(|children| children.ids.clone())
3500                .unwrap_or_default(),
3501            child_state_ptrs: self
3502                .child_states()
3503                .iter()
3504                .map(|state| Rc::as_ptr(state) as *const () as usize)
3505                .collect(),
3506            child_measurable_ptrs: self
3507                .child_measurables()
3508                .iter()
3509                .map(|measurable| {
3510                    measurable.as_ref() as *const dyn Measurable as *const () as usize
3511                })
3512                .collect(),
3513            child_measurable_count: self.child_measurables().len(),
3514            coordinator_node_ptrs: self.coordinator_chain.debug_ptrs(),
3515            coordinator_node_count: self.coordinator_chain.nodes.len(),
3516        }
3517    }
3518}
3519
3520#[cfg(test)]
3521#[derive(Debug, Clone, PartialEq, Eq)]
3522pub(crate) struct LayoutRuntimeDebugStats {
3523    pub(crate) child_ids: Vec<NodeId>,
3524    pub(crate) child_state_ptrs: Vec<usize>,
3525    pub(crate) child_measurable_ptrs: Vec<usize>,
3526    pub(crate) child_measurable_count: usize,
3527    pub(crate) coordinator_node_ptrs: Vec<usize>,
3528    pub(crate) coordinator_node_count: usize,
3529}
3530
3531#[derive(Default)]
3532struct LayoutChildFrame {
3533    builder: RefCell<Option<Rc<LayoutBuilderState>>>,
3534    error: RefCell<Option<NodeError>>,
3535    pass: Cell<ChildPass>,
3536    /// The node whose children the frame binds, which places them.
3537    parent: Cell<Option<NodeId>>,
3538}
3539
3540/// What a node binds its children for.
3541#[derive(Clone, Copy, Default, PartialEq, Eq)]
3542enum ChildPass {
3543    /// A measure of the node, which records how it read each child, for a
3544    /// later keep of its measurement.
3545    #[default]
3546    Measure,
3547    /// An intrinsic size of the node, which its parent asks: the record of
3548    /// the node's last measure stays as it was.
3549    Intrinsics,
3550}
3551
3552impl LayoutChildFrame {
3553    fn bind(&self, builder: &Rc<LayoutBuilderState>, parent: NodeId, pass: ChildPass) {
3554        self.error.borrow_mut().take();
3555        *self.builder.borrow_mut() = Some(Rc::clone(builder));
3556        self.pass.set(pass);
3557        self.parent.set(Some(parent));
3558    }
3559
3560    fn measures(&self) -> bool {
3561        self.pass.get() == ChildPass::Measure
3562    }
3563
3564    fn unbind(&self) {
3565        self.builder.borrow_mut().take();
3566    }
3567
3568    fn record_error(&self, err: NodeError) {
3569        if self.builder.borrow().is_none() {
3570            return;
3571        }
3572        let mut slot = self.error.borrow_mut();
3573        if slot.is_none() {
3574            *slot = Some(err);
3575        }
3576    }
3577}
3578
3579struct LayoutChildBinding<'a> {
3580    cache: &'a LayoutNodeCacheHandles,
3581    layout_state: Option<&'a Rc<RefCell<LayoutState>>>,
3582    parent_data: Option<cranpose_ui_layout::ParentData>,
3583    /// The child's own layout or measure is dirty.
3584    dirty: bool,
3585    /// Only nodes below the child are dirty.
3586    descendant_dirty: bool,
3587}
3588
3589/// Reads a child that is a layout node or a subcompose node: its flags,
3590/// cache, parent data and placement. `None` for another node type.
3591fn read_layout_child<R>(
3592    applier: &mut MemoryApplier,
3593    child_id: NodeId,
3594    read: impl Fn(
3595        &dyn Node,
3596        &LayoutNodeCacheHandles,
3597        &dyn Fn() -> cranpose_ui_layout::ParentData,
3598        bool,
3599    ) -> R,
3600) -> Result<Option<R>, NodeError> {
3601    match applier.with_node::<LayoutNode, _>(child_id, |child| {
3602        read(
3603            &*child,
3604            child.cache_handles(),
3605            &|| child.parent_data(),
3606            child.is_placed(),
3607        )
3608    }) {
3609        Ok(value) => Ok(Some(value)),
3610        Err(NodeError::TypeMismatch { .. }) => {
3611            match applier.with_node::<SubcomposeLayoutNode, _>(child_id, |child| {
3612                read(
3613                    &*child,
3614                    child.cache_handles(),
3615                    &|| child.parent_data(),
3616                    child.layout_state().is_placed(),
3617                )
3618            }) {
3619                Ok(value) => Ok(Some(value)),
3620                Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => Ok(None),
3621                Err(err) => Err(err),
3622            }
3623        }
3624        Err(NodeError::Missing { .. }) => Ok(None),
3625        Err(err) => Err(err),
3626    }
3627}
3628
3629/// A parent's record of one child, for each child of every parent: its
3630/// shared parts sit in `Cell`s, read by take and put back, where a
3631/// `RefCell`'s borrow flag would take a word of every record.
3632struct LayoutChildMeasureState {
3633    node_id: NodeId,
3634    frame: Rc<LayoutChildFrame>,
3635    /// The child's cache, `None` until the record is first bound.
3636    cache: Cell<Option<LayoutNodeCacheHandles>>,
3637    cache_epoch: Cell<u64>,
3638    force_remeasure: Cell<bool>,
3639    parent_data: Cell<Option<cranpose_ui_layout::ParentData>>,
3640    /// The constraints the parent's last measure gave the child.
3641    measured_constraints: Cell<Option<Constraints>>,
3642    /// Whether the parent's last measure read the child's intrinsic sizes.
3643    read_intrinsics: Cell<bool>,
3644    measured: Cell<Option<Rc<MeasuredNode>>>,
3645    last_position: Cell<Option<Point>>,
3646    layout_state: Cell<Option<Rc<RefCell<LayoutState>>>>,
3647}
3648
3649/// Runs `read` on what `cell` holds and puts it back. `read` must not reach
3650/// the same cell again.
3651pub(crate) fn read_cell<T: Default, R>(cell: &Cell<T>, read: impl FnOnce(&T) -> R) -> R {
3652    let value = cell.take();
3653    let result = read(&value);
3654    cell.set(value);
3655    result
3656}
3657
3658impl LayoutChildMeasureState {
3659    fn placement_position(&self, placement: Option<&Placement>) -> Point {
3660        placement
3661            .map(|placement| Point {
3662                x: placement.x,
3663                y: placement.y,
3664            })
3665            .or_else(|| self.last_position.get())
3666            .unwrap_or_default()
3667    }
3668
3669    fn new(node_id: NodeId, frame: Rc<LayoutChildFrame>) -> Rc<Self> {
3670        Rc::new(Self {
3671            node_id,
3672            frame,
3673            cache: Cell::new(None),
3674            cache_epoch: Cell::new(0),
3675            force_remeasure: Cell::new(true),
3676            parent_data: Cell::new(None),
3677            measured_constraints: Cell::new(None),
3678            read_intrinsics: Cell::new(false),
3679            measured: Cell::new(None),
3680            last_position: Cell::new(None),
3681            layout_state: Cell::new(None),
3682        })
3683    }
3684
3685    /// Binds the child for a measure of its parent. A child with only dirty
3686    /// nodes below it keeps its cache: it measures again, but may keep its
3687    /// measurement.
3688    fn bind(&self, binding: LayoutChildBinding<'_>, pass: &LayoutBuilderState) {
3689        let child_epoch = binding.cache.epoch();
3690        let stale = binding.dirty || child_epoch < pass.cache_floor;
3691        let cache_epoch = if stale { pass.cache_epoch } else { child_epoch };
3692        binding.cache.activate(cache_epoch);
3693        let mut cache = self.cache.take();
3694        match &mut cache {
3695            Some(cache) => cache.clone_from(binding.cache),
3696            None => cache = Some(binding.cache.clone()),
3697        }
3698        self.cache.set(cache);
3699        self.cache_epoch.set(cache_epoch);
3700        self.force_remeasure.set(stale || binding.descendant_dirty);
3701        self.parent_data.set(binding.parent_data);
3702        if self.frame.measures() {
3703            self.measured.take();
3704            self.last_position.set(None);
3705            self.measured_constraints.set(None);
3706            self.read_intrinsics.set(false);
3707        }
3708        let layout_state = self.layout_state.take();
3709        let shared = layout_state
3710            .as_ref()
3711            .zip(binding.layout_state)
3712            .is_some_and(|(current, bound)| Rc::ptr_eq(current, bound));
3713        self.layout_state.set(if shared {
3714            layout_state
3715        } else {
3716            binding.layout_state.cloned()
3717        });
3718    }
3719
3720    /// Runs `f` on the child's layout state with the context of the pass it
3721    /// measures in; nothing while it is bound to no pass.
3722    fn with_pass_layout_state(&self, f: impl FnOnce(&mut LayoutState, &AppContext)) {
3723        let builder = self.frame.builder.borrow();
3724        let Some(builder) = builder.as_ref() else {
3725            return;
3726        };
3727        read_cell(&self.layout_state, |state| {
3728            if let Some(state) = state {
3729                f(&mut state.borrow_mut(), &builder.context);
3730            }
3731        });
3732    }
3733
3734    fn place_retained(&self, position: Point) {
3735        self.last_position.set(Some(position));
3736        let builder = self.frame.builder.borrow();
3737        let Some(builder) = builder.as_ref() else {
3738            return;
3739        };
3740        let placed = read_cell(&self.layout_state, |layout_state| {
3741            layout_state
3742                .as_ref()
3743                .map(|layout_state| {
3744                    layout_state.borrow_mut().place(
3745                        position,
3746                        self.frame.parent.get(),
3747                        &builder.context,
3748                    );
3749                })
3750                .is_some()
3751        });
3752        if placed {
3753            return;
3754        }
3755        let Ok(mut applier) = builder.applier.try_borrow_typed() else {
3756            return;
3757        };
3758        let _ = applier.with_node::<SubcomposeLayoutNode, _>(self.node_id, |node| {
3759            node.set_position(position, self.frame.parent.get(), &builder.context);
3760        });
3761    }
3762
3763    /// The intrinsic size of a child that is a layout node, from its
3764    /// modifier chain and measure policy, without measuring it. `None` for
3765    /// another node type, which measures for it.
3766    fn layout_intrinsic(&self, kind: IntrinsicKind) -> Option<f32> {
3767        let builder = self.frame.builder.borrow();
3768        let builder = builder.as_ref()?;
3769        match builder.layout_node_intrinsic(self.node_id, kind) {
3770            Ok(value) => value,
3771            Err(err) => {
3772                self.frame.record_error(err);
3773                Some(0.0)
3774            }
3775        }
3776    }
3777
3778    fn perform_measure(&self, constraints: Constraints) -> Result<Rc<MeasuredNode>, NodeError> {
3779        let builder = self.frame.builder.borrow();
3780        let builder = builder.as_ref().ok_or(NodeError::MissingContext {
3781            id: self.node_id,
3782            reason: "layout child applier not configured",
3783        })?;
3784        builder.measure_node(self.node_id, constraints)
3785    }
3786
3787    fn measure_cached(&self, constraints: Constraints) -> Option<Rc<MeasuredNode>> {
3788        if self.frame.measures() {
3789            self.measured_constraints.set(Some(constraints));
3790        }
3791        let cache = read_cell(&self.cache, Clone::clone);
3792        if let Some(cache) = &cache {
3793            cache.activate(self.cache_epoch.get());
3794        }
3795        if !self.force_remeasure.get()
3796            && let Some(cached) = cache
3797                .as_ref()
3798                .and_then(|cache| cache.get_measurement(constraints))
3799        {
3800            // A measure clears the placed flag the parent's placement sets
3801            // again; a child it no longer places then leaves the scene.
3802            if self.frame.measures() {
3803                self.with_pass_layout_state(LayoutState::clear_placed);
3804            }
3805            return Some(cached);
3806        }
3807
3808        match self.perform_measure(constraints) {
3809            Ok(measured) => {
3810                self.force_remeasure.set(false);
3811                if let Some(cache) = &cache {
3812                    cache.store_measurement(constraints, Rc::clone(&measured));
3813                }
3814                Some(measured)
3815            }
3816            Err(err) => {
3817                self.frame.record_error(err);
3818                None
3819            }
3820        }
3821    }
3822}
3823
3824struct LayoutChildMeasurable {
3825    state: Rc<LayoutChildMeasureState>,
3826}
3827
3828impl LayoutChildMeasurable {
3829    fn new(state: Rc<LayoutChildMeasureState>) -> Self {
3830        Self { state }
3831    }
3832
3833    fn resolved_parent_data(&self) -> Option<cranpose_ui_layout::ParentData> {
3834        if self.state.frame.builder.borrow().is_none() {
3835            return None;
3836        }
3837        read_cell(&self.state.parent_data, Clone::clone)
3838    }
3839
3840    fn intrinsic(
3841        &self,
3842        kind: IntrinsicKind,
3843        constraints: Constraints,
3844        extent: fn(Size) -> f32,
3845    ) -> f32 {
3846        let state = &self.state;
3847        if state.frame.measures() {
3848            state.read_intrinsics.set(true);
3849        }
3850        let cache = read_cell(&state.cache, Clone::clone);
3851        if let Some(cache) = &cache {
3852            cache.activate(state.cache_epoch.get());
3853        }
3854        if !state.force_remeasure.get()
3855            && let Some(value) = cache.as_ref().and_then(|cache| cache.get_intrinsic(&kind))
3856        {
3857            return value;
3858        }
3859        let value = match state.layout_intrinsic(kind) {
3860            Some(value) => value,
3861            None => state
3862                .measure_cached(constraints)
3863                .map_or(0.0, |node| extent(node.size_for_parent())),
3864        };
3865        if let Some(cache) = &cache {
3866            cache.store_intrinsic(kind, value);
3867        }
3868        value
3869    }
3870}
3871
3872impl PlaceTarget for LayoutChildMeasureState {
3873    fn place(&self, x: f32, y: f32) {
3874        let internal_offset = read_cell(&self.measured, |measured| {
3875            measured
3876                .as_ref()
3877                .map(|measured| measured.offset)
3878                .unwrap_or_default()
3879        });
3880        self.place_retained(Point {
3881            x: x + internal_offset.x,
3882            y: y + internal_offset.y,
3883        });
3884    }
3885}
3886
3887impl Measurable for LayoutChildMeasurable {
3888    fn measured_hold(&self) -> Option<(Size, cranpose_ui_layout::ConstraintsHold)> {
3889        read_cell(&self.state.measured, |measured| {
3890            let measured = measured.as_ref()?;
3891            let hold = read_cell(&self.state.cache, |cache| cache.as_ref()?.hold_of(measured))?;
3892            Some((measured.size_for_parent(), hold))
3893        })
3894    }
3895
3896    fn measure(&self, constraints: Constraints) -> Placeable {
3897        let state = &self.state;
3898        let measured = state.measure_cached(constraints);
3899        let (measured_size, size_for_parent) = measured.as_ref().map_or(
3900            (
3901                Size {
3902                    width: 0.0,
3903                    height: 0.0,
3904                },
3905                Size {
3906                    width: 0.0,
3907                    height: 0.0,
3908                },
3909            ),
3910            |measured| (measured.size, measured.size_for_parent()),
3911        );
3912        state.with_pass_layout_state(|layout_state, context| {
3913            layout_state.set_size(measured_size, context);
3914        });
3915        let alignment_lines = measured
3916            .as_ref()
3917            .map_or_else(AlignmentLines::default, |node| {
3918                node.alignment_lines_for_parent()
3919            });
3920        state.measured.set(measured);
3921
3922        Placeable::with_place_target(
3923            size_for_parent.width,
3924            size_for_parent.height,
3925            state.node_id,
3926            Rc::clone(&self.state) as Rc<dyn PlaceTarget>,
3927        )
3928        .with_alignment_lines(alignment_lines)
3929    }
3930
3931    fn min_intrinsic_width(&self, height: f32) -> f32 {
3932        self.intrinsic(
3933            IntrinsicKind::MinWidth(height),
3934            Constraints {
3935                min_width: 0.0,
3936                max_width: f32::INFINITY,
3937                min_height: height,
3938                max_height: height,
3939            },
3940            |size| size.width,
3941        )
3942    }
3943
3944    fn max_intrinsic_width(&self, height: f32) -> f32 {
3945        self.intrinsic(
3946            IntrinsicKind::MaxWidth(height),
3947            Constraints {
3948                min_width: 0.0,
3949                max_width: f32::INFINITY,
3950                min_height: 0.0,
3951                max_height: height,
3952            },
3953            |size| size.width,
3954        )
3955    }
3956
3957    fn min_intrinsic_height(&self, width: f32) -> f32 {
3958        self.intrinsic(
3959            IntrinsicKind::MinHeight(width),
3960            Constraints {
3961                min_width: width,
3962                max_width: width,
3963                min_height: 0.0,
3964                max_height: f32::INFINITY,
3965            },
3966            |size| size.height,
3967        )
3968    }
3969
3970    fn max_intrinsic_height(&self, width: f32) -> f32 {
3971        self.intrinsic(
3972            IntrinsicKind::MaxHeight(width),
3973            Constraints {
3974                min_width: 0.0,
3975                max_width: width,
3976                min_height: 0.0,
3977                max_height: f32::INFINITY,
3978            },
3979            |size| size.height,
3980        )
3981    }
3982
3983    fn flex_parent_data(&self) -> Option<cranpose_ui_layout::FlexParentData> {
3984        let parent_data = self.resolved_parent_data()?;
3985        if !parent_data.has_weight() {
3986            return None;
3987        }
3988        Some(cranpose_ui_layout::FlexParentData::new(
3989            parent_data.weight,
3990            parent_data.fill,
3991        ))
3992    }
3993
3994    fn parent_data(&self) -> cranpose_ui_layout::ParentData {
3995        self.resolved_parent_data().unwrap_or_default()
3996    }
3997}
3998
3999#[derive(Clone)]
4000struct RuntimeNodeMetadata {
4001    modifier: Modifier,
4002    resolved_modifiers: ResolvedModifiers,
4003    modifier_slices: Rc<ModifierNodeSlices>,
4004    semantics: Option<Rc<SemanticsConfiguration>>,
4005    role: SemanticsRole,
4006    button_handler: Option<Rc<RefCell<dyn FnMut()>>>,
4007}
4008
4009impl Default for RuntimeNodeMetadata {
4010    fn default() -> Self {
4011        Self {
4012            modifier: Modifier::empty(),
4013            resolved_modifiers: ResolvedModifiers::default(),
4014            modifier_slices: Rc::default(),
4015            semantics: None,
4016            role: SemanticsRole::Unknown,
4017            button_handler: None,
4018        }
4019    }
4020}
4021
4022fn role_from_modifier_slices(modifier_slices: &ModifierNodeSlices) -> SemanticsRole {
4023    modifier_slices
4024        .annotated_text()
4025        .map_or(SemanticsRole::Layout, |text| SemanticsRole::Text {
4026            value: SemanticsText(Rc::clone(&text)),
4027        })
4028}
4029
4030fn runtime_metadata_for(
4031    applier: &mut MemoryApplier,
4032    node_id: NodeId,
4033) -> Result<RuntimeNodeMetadata, NodeError> {
4034    if let Ok(meta) = applier.with_node::<LayoutNode, _>(node_id, |layout| {
4035        let modifier = layout.modifier.clone();
4036        let resolved_modifiers = layout.resolved_modifiers();
4037        let modifier_slices = layout.modifier_slices_snapshot();
4038        let role = role_from_modifier_slices(&modifier_slices);
4039
4040        RuntimeNodeMetadata {
4041            modifier,
4042            resolved_modifiers,
4043            modifier_slices,
4044            semantics: layout.semantics_configuration().map(Rc::new),
4045            role,
4046            button_handler: None,
4047        }
4048    }) {
4049        return Ok(meta);
4050    }
4051
4052    if let Ok((modifier, resolved_modifiers, modifier_slices, semantics)) =
4053        applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
4054            (
4055                node.modifier(),
4056                node.resolved_modifiers(),
4057                node.modifier_slices_snapshot(),
4058                node.semantics_configuration().map(Rc::new),
4059            )
4060        })
4061    {
4062        return Ok(RuntimeNodeMetadata {
4063            modifier,
4064            resolved_modifiers,
4065            modifier_slices,
4066            semantics,
4067            role: SemanticsRole::Subcompose,
4068            button_handler: None,
4069        });
4070    }
4071    Ok(RuntimeNodeMetadata::default())
4072}
4073
4074/// Runs `visit` on the measurement `child` holds in its cache, or on a leaf
4075/// of no size for a child that holds none, as a node of another kind
4076/// measures.
4077fn visit_child<R>(
4078    applier: &mut MemoryApplier,
4079    child: &MeasuredChild,
4080    visit: impl FnOnce(&mut MemoryApplier, &MeasuredNode) -> R,
4081) -> R {
4082    let held = applier.get_mut(child.node_id).ok().and_then(|node| {
4083        let any = node.as_any_mut();
4084        if let Some(layout) = any.downcast_ref::<LayoutNode>() {
4085            return layout.cache_handles().held_measurement();
4086        }
4087        any.downcast_ref::<SubcomposeLayoutNode>()
4088            .and_then(|subcompose| subcompose.cache_handles().held_measurement())
4089    });
4090    match held {
4091        Some(held) => visit(applier, &held),
4092        None => visit(
4093            applier,
4094            &MeasuredNode::new(
4095                child.node_id,
4096                Size::default(),
4097                Point::default(),
4098                Point::default(),
4099                Vec::new(),
4100            ),
4101        ),
4102    }
4103}
4104
4105fn clear_semantics_dirty_flags(
4106    applier: &mut MemoryApplier,
4107    node: &MeasuredNode,
4108) -> Result<(), NodeError> {
4109    match applier.with_node::<LayoutNode, _>(node.node_id, |layout| {
4110        layout.clear_needs_semantics();
4111    }) {
4112        Ok(()) => {}
4113        Err(NodeError::Missing { .. }) => {}
4114        Err(NodeError::TypeMismatch { .. }) => {
4115            match applier.with_node::<SubcomposeLayoutNode, _>(node.node_id, |subcompose| {
4116                subcompose.clear_needs_semantics();
4117            }) {
4118                Ok(()) | Err(NodeError::Missing { .. } | NodeError::TypeMismatch { .. }) => {}
4119                Err(err) => return Err(err),
4120            }
4121        }
4122        Err(err) => return Err(err),
4123    }
4124
4125    for child in &node.children {
4126        visit_child(applier, child, clear_semantics_dirty_flags)?;
4127    }
4128
4129    Ok(())
4130}
4131
4132fn build_semantics_tree_from_live_nodes(
4133    applier: &mut MemoryApplier,
4134    node: &MeasuredNode,
4135) -> Result<SemanticsTree, NodeError> {
4136    Ok(SemanticsTree::new(build_semantics_node_from_live_nodes(
4137        applier, node, None,
4138    )?))
4139}
4140
4141fn semantics_node_from_parts(
4142    node_id: NodeId,
4143    node_generation: u32,
4144    mut role: SemanticsRole,
4145    config: Option<SemanticsConfiguration>,
4146    children: Vec<SemanticsNode>,
4147    held_details: Option<Box<SemanticsDetails>>,
4148    bounds: GeometryRect,
4149) -> SemanticsNode {
4150    let focusable = crate::focus_dispatch::has_focus_target(node_id);
4151    let mut node = SemanticsNode {
4152        node_id,
4153        bounds,
4154        node_generation,
4155        children,
4156        focusable,
4157        focused: focusable && crate::focus_dispatch::active_focus_target() == Some(node_id),
4158        details: held_details,
4159        ..SemanticsNode::default()
4160    };
4161    let details = match config {
4162        Some(mut config) => {
4163            if config.role == Some(SemanticsWidgetRole::Button) {
4164                role = SemanticsRole::Button;
4165            }
4166            if config.is_activatable() {
4167                node.actions.push(SemanticsAction::Click {
4168                    handler: SemanticsCallback::new(node_id),
4169                });
4170            }
4171            let on_click_label = config.on_click_label.take().or_else(|| {
4172                config
4173                    .on_click
4174                    .as_ref()
4175                    .and_then(|action| (!action.label.is_empty()).then(|| action.label.clone()))
4176            });
4177            node.widget_role = config.role;
4178            node.description = config.content_description.take();
4179            node.on_click = config.on_click.take();
4180            node.selected = config.selected;
4181            node.toggled = config.toggled;
4182            node.enabled = config.enabled;
4183            node.hidden = config.hidden;
4184            node.merge_descendants = config.merge_descendants;
4185            node.traversal_index = config.traversal_index;
4186            node.text = config.text.take();
4187            let is_modal = config.is_modal
4188                && modal_takes_space(Size {
4189                    width: bounds.width,
4190                    height: bounds.height,
4191                });
4192            SemanticsDetails::from_configuration(config, on_click_label, is_modal)
4193        }
4194        None => SemanticsDetails::NONE,
4195    };
4196    node.set_details(details);
4197    node.role = role;
4198    node
4199}
4200
4201#[inline(never)]
4202fn build_semantics_node_from_live_nodes(
4203    applier: &mut MemoryApplier,
4204    node: &MeasuredNode,
4205    origin: Option<Point>,
4206) -> Result<SemanticsNode, NodeError> {
4207    let (role, config, (bounds, content), placement) =
4208        match applier.with_node::<LayoutNode, _>(node.node_id, |layout| {
4209            let role = role_from_modifier_slices(&layout.modifier_slices_snapshot());
4210            let config = layout.semantics_configuration();
4211            layout.clear_needs_semantics();
4212            let state = layout.layout_state();
4213            (
4214                role,
4215                config,
4216                semantics_placement(&state, origin),
4217                SemanticsPlacement::of(&state),
4218            )
4219        }) {
4220            Ok(data) => data,
4221            Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => {
4222                match applier.with_node::<SubcomposeLayoutNode, _>(node.node_id, |subcompose| {
4223                    subcompose.clear_needs_semantics();
4224                    let state = subcompose.layout_state();
4225                    (
4226                        SemanticsRole::Subcompose,
4227                        subcompose.semantics_configuration(),
4228                        semantics_placement(&state, origin),
4229                        SemanticsPlacement::of(&state),
4230                    )
4231                }) {
4232                    Ok(data) => data,
4233                    Err(NodeError::TypeMismatch { .. } | NodeError::Missing { .. }) => {
4234                        let top_left = origin.unwrap_or_default();
4235                        (
4236                            SemanticsRole::Unknown,
4237                            None,
4238                            (
4239                                GeometryRect::from_origin_size(top_left, node.size),
4240                                top_left,
4241                            ),
4242                            SemanticsPlacement::default(),
4243                        )
4244                    }
4245                    Err(err) => return Err(err),
4246                }
4247            }
4248            Err(err) => return Err(err),
4249        };
4250
4251    let mut children = Vec::with_capacity(node.children.len());
4252    for child in &node.children {
4253        children.push(visit_child(applier, child, |applier, child| {
4254            build_semantics_node_from_live_nodes(applier, child, Some(content))
4255        })?);
4256    }
4257
4258    Ok(SemanticsNode {
4259        placement,
4260        ..semantics_node_from_parts(
4261            node.node_id,
4262            applier.node_generation(node.node_id),
4263            role,
4264            config,
4265            children,
4266            None,
4267            bounds,
4268        )
4269    })
4270}
4271
4272fn record_semantics_allocation_stats(node: &SemanticsNode, stats: &mut LayoutAllocationDebugStats) {
4273    stats.semantics_node_count += 1;
4274    stats.semantics_action_count += node.actions.len();
4275    stats.semantics_action_capacity += node.actions.capacity();
4276    stats.semantics_child_count += node.children.len();
4277    stats.semantics_child_capacity += node.children.capacity();
4278    stats.semantics_heap_bytes += node.actions.capacity() * size_of::<SemanticsAction>();
4279    stats.semantics_heap_bytes += node.children.capacity() * size_of::<SemanticsNode>();
4280    if node.details.is_some() {
4281        stats.semantics_heap_bytes += size_of::<SemanticsDetails>();
4282    }
4283
4284    if let Some(description) = &node.description {
4285        stats.semantics_description_count += 1;
4286        stats.semantics_description_bytes += description.capacity();
4287        stats.semantics_heap_bytes += description.capacity();
4288    }
4289
4290    for child in &node.children {
4291        record_semantics_allocation_stats(child, stats);
4292    }
4293}
4294
4295fn record_layout_box_allocation_stats(
4296    layout_box: &LayoutBox,
4297    stats: &mut LayoutAllocationDebugStats,
4298) {
4299    stats.layout_box_count += 1;
4300    stats.layout_box_child_count += layout_box.children.len();
4301    stats.layout_box_child_capacity += layout_box.children.capacity();
4302    stats.layout_box_heap_bytes += layout_box.children.capacity() * size_of::<LayoutBox>();
4303    stats.add_modifier_slice(layout_box.node_data.modifier_slices().debug_stats());
4304
4305    for child in &layout_box.children {
4306        record_layout_box_allocation_stats(child, stats);
4307    }
4308}
4309
4310fn build_layout_tree(
4311    applier: &mut MemoryApplier,
4312    node: &MeasuredNode,
4313) -> Result<LayoutTree, NodeError> {
4314    fn place(
4315        applier: &mut MemoryApplier,
4316        node: &MeasuredNode,
4317        origin: Point,
4318        parent_transform: ProjectiveTransform,
4319    ) -> Result<LayoutBox, NodeError> {
4320        let top_left = Point {
4321            x: origin.x + node.offset.x,
4322            y: origin.y + node.offset.y,
4323        };
4324        let rect = GeometryRect {
4325            x: top_left.x,
4326            y: top_left.y,
4327            width: node.size.width,
4328            height: node.size.height,
4329        };
4330        let (data, window_transform) =
4331            snapshot_node_data(applier, node.node_id, top_left, node.size, parent_transform)?;
4332        let mut children = Vec::with_capacity(node.children.len());
4333        for child in &node.children {
4334            if crate::modifier::is_window_root(applier, child.node_id) {
4335                continue;
4336            }
4337            let child_origin = Point {
4338                x: top_left.x + child.offset.x,
4339                y: top_left.y + child.offset.y,
4340            };
4341            children.push(visit_child(applier, child, |applier, child| {
4342                place(applier, child, child_origin, window_transform)
4343            })?);
4344        }
4345        Ok(LayoutBox {
4346            node_generation: applier.node_generation(node.node_id),
4347            ..LayoutBox::new(node.node_id, rect, node.content_offset, data, children)
4348        })
4349    }
4350
4351    Ok(LayoutTree::new(place(
4352        applier,
4353        node,
4354        Point { x: 0.0, y: 0.0 },
4355        ProjectiveTransform::identity(),
4356    )?))
4357}
4358
4359fn semantics_role_from_layout_box(layout_box: &LayoutBox) -> SemanticsRole {
4360    match &layout_box.node_data.kind {
4361        LayoutNodeKind::Subcompose => SemanticsRole::Subcompose,
4362        LayoutNodeKind::Spacer => SemanticsRole::Spacer,
4363        LayoutNodeKind::Unknown => SemanticsRole::Unknown,
4364        LayoutNodeKind::Button { .. } => SemanticsRole::Button,
4365        LayoutNodeKind::Layout => role_from_modifier_slices(layout_box.node_data.modifier_slices()),
4366    }
4367}
4368
4369#[inline(never)]
4370fn build_semantics_node_from_layout_box(layout_box: &LayoutBox, origin: Point) -> SemanticsNode {
4371    let rect = layout_box.rect;
4372    let content = Point {
4373        x: rect.x + layout_box.content_offset.x,
4374        y: rect.y + layout_box.content_offset.y,
4375    };
4376    let children = layout_box
4377        .children
4378        .iter()
4379        .map(|child| build_semantics_node_from_layout_box(child, content))
4380        .collect();
4381
4382    SemanticsNode {
4383        placement: SemanticsPlacement {
4384            position: Point {
4385                x: rect.x - origin.x,
4386                y: rect.y - origin.y,
4387            },
4388            content_offset: layout_box.content_offset,
4389        },
4390        ..semantics_node_from_parts(
4391            layout_box.node_id,
4392            layout_box.node_generation,
4393            semantics_role_from_layout_box(layout_box),
4394            layout_box.node_data.semantics().cloned(),
4395            children,
4396            None,
4397            rect,
4398        )
4399    }
4400}
4401
4402fn layout_kind_from_metadata(_node_id: NodeId, info: &RuntimeNodeMetadata) -> LayoutNodeKind {
4403    match &info.role {
4404        SemanticsRole::Layout => LayoutNodeKind::Layout,
4405        SemanticsRole::Subcompose => LayoutNodeKind::Subcompose,
4406        SemanticsRole::Text { .. } => LayoutNodeKind::Layout,
4407        SemanticsRole::Spacer => LayoutNodeKind::Spacer,
4408        SemanticsRole::Button => {
4409            let handler = info
4410                .button_handler
4411                .as_ref()
4412                .cloned()
4413                .unwrap_or_else(|| Rc::new(RefCell::new(|| {})));
4414            LayoutNodeKind::Button { on_click: handler }
4415        }
4416        SemanticsRole::Unknown => LayoutNodeKind::Unknown,
4417    }
4418}
4419
4420fn subtract_padding(constraints: Constraints, padding: EdgeInsets) -> Constraints {
4421    let horizontal = padding.horizontal_sum();
4422    let vertical = padding.vertical_sum();
4423    let min_width = (constraints.min_width - horizontal).max(0.0);
4424    let mut max_width = constraints.max_width;
4425    if max_width.is_finite() {
4426        max_width = (max_width - horizontal).max(0.0);
4427    }
4428    let min_height = (constraints.min_height - vertical).max(0.0);
4429    let mut max_height = constraints.max_height;
4430    if max_height.is_finite() {
4431        max_height = (max_height - vertical).max(0.0);
4432    }
4433    normalize_constraints(Constraints {
4434        min_width,
4435        max_width,
4436        min_height,
4437        max_height,
4438    })
4439}
4440
4441fn resolve_dimension(
4442    base: f32,
4443    explicit: DimensionConstraint,
4444    min_override: Option<f32>,
4445    max_override: Option<f32>,
4446    min_limit: f32,
4447    max_limit: f32,
4448) -> f32 {
4449    let mut min_bound = min_limit;
4450    if let Some(min_value) = min_override {
4451        min_bound = min_bound.max(min_value);
4452    }
4453
4454    let mut max_bound = if max_limit.is_finite() {
4455        max_limit
4456    } else {
4457        max_override.unwrap_or(max_limit)
4458    };
4459    if let Some(max_value) = max_override {
4460        if max_bound.is_finite() {
4461            max_bound = max_bound.min(max_value);
4462        } else {
4463            max_bound = max_value;
4464        }
4465    }
4466    if max_bound < min_bound {
4467        max_bound = min_bound;
4468    }
4469
4470    let mut size = match explicit {
4471        DimensionConstraint::Points(points) => points,
4472        DimensionConstraint::Fraction(fraction) => {
4473            if max_limit.is_finite() {
4474                max_limit * fraction.clamp(0.0, 1.0)
4475            } else {
4476                base
4477            }
4478        }
4479        DimensionConstraint::Unspecified => base,
4480        DimensionConstraint::Intrinsic(_) => base,
4481    };
4482
4483    size = clamp_dimension(size, min_bound, max_bound);
4484    size = clamp_dimension(size, min_limit, max_limit);
4485    size.max(0.0)
4486}
4487
4488fn clamp_dimension(value: f32, min: f32, max: f32) -> f32 {
4489    let mut result = value.max(min);
4490    if max.is_finite() {
4491        result = result.min(max);
4492    }
4493    result
4494}
4495
4496fn normalize_constraints(mut constraints: Constraints) -> Constraints {
4497    if constraints.max_width < constraints.min_width {
4498        constraints.max_width = constraints.min_width;
4499    }
4500    if constraints.max_height < constraints.min_height {
4501        constraints.max_height = constraints.min_height;
4502    }
4503    constraints
4504}
4505
4506#[cfg(test)]
4507#[path = "tests/layout_tests.rs"]
4508mod tests;
4509
4510#[cfg(test)]
4511#[path = "tests/semantics_update_tests.rs"]
4512mod semantics_update_tests;
4513
4514#[cfg(test)]
4515#[path = "tests/coordinator_geometry_tests.rs"]
4516mod coordinator_geometry_tests;