1pub mod coordinator;
4pub mod core;
5pub mod policies;
6
7use cranpose_core::collections::map::HashMap;
8use std::{
9 cell::{Cell, RefCell},
10 fmt,
11 mem::size_of,
12 rc::Rc,
13 sync::atomic::{AtomicU64, Ordering},
14};
15
16use cranpose_core::{
17 Applier, ApplierHost, Composer, ConcreteApplierHost, MemoryApplier, Node, NodeError, NodeId,
18 Phase, RuntimeHandle, SlotTable, SlotsHost, SnapshotStateObserver,
19};
20
21use self::coordinator::NodeCoordinator;
22use self::core::Measurable;
23use self::core::Placeable;
24#[cfg(test)]
25use self::core::{HorizontalAlignment, VerticalAlignment};
26use crate::modifier::{
27 collect_semantics_from_modifier, DimensionConstraint, EdgeInsets, Modifier, ModifierNodeSlices,
28 ModifierNodeSlicesDebugStats, Point, Rect as GeometryRect, ResolvedModifiers, Size,
29};
30
31use crate::subcompose_layout::SubcomposeLayoutNode;
32use crate::widgets::nodes::{IntrinsicKind, LayoutNode, LayoutNodeCacheHandles};
33use cranpose_foundation::{
34 InvalidationKind, ModifierNodeContext, NodeCapabilities, SemanticsConfiguration,
35};
36use cranpose_ui_layout::{Constraints, MeasurePolicy, MeasureResult};
37
38#[derive(Default)]
43pub(crate) struct LayoutNodeContext {
44 invalidations: Vec<InvalidationKind>,
45 update_requested: bool,
46 active_capabilities: Vec<NodeCapabilities>,
47}
48
49impl LayoutNodeContext {
50 pub(crate) fn new() -> Self {
51 Self::default()
52 }
53
54 pub(crate) fn take_invalidations(&mut self) -> Vec<InvalidationKind> {
55 std::mem::take(&mut self.invalidations)
56 }
57}
58
59impl ModifierNodeContext for LayoutNodeContext {
60 fn invalidate(&mut self, kind: InvalidationKind) {
61 if !self.invalidations.contains(&kind) {
62 self.invalidations.push(kind);
63 }
64 }
65
66 fn request_update(&mut self) {
67 self.update_requested = true;
68 }
69
70 fn push_active_capabilities(&mut self, capabilities: NodeCapabilities) {
71 self.active_capabilities.push(capabilities);
72 }
73
74 fn pop_active_capabilities(&mut self) {
75 self.active_capabilities.pop();
76 }
77}
78
79static NEXT_CACHE_EPOCH: AtomicU64 = AtomicU64::new(1);
80
81#[doc(hidden)]
104pub fn invalidate_all_layout_caches() {
105 NEXT_CACHE_EPOCH.fetch_add(1, Ordering::Relaxed);
106}
107
108struct ApplierSlotGuard<'a> {
119 target: &'a mut MemoryApplier,
121 host: Rc<ConcreteApplierHost<MemoryApplier>>,
123 slots: Rc<RefCell<SlotTable>>,
126}
127
128impl<'a> ApplierSlotGuard<'a> {
129 fn new(target: &'a mut MemoryApplier) -> Self {
133 let original_applier = std::mem::replace(target, MemoryApplier::new());
135 let host = Rc::new(ConcreteApplierHost::new(original_applier));
136
137 let slots = {
139 let mut applier_ref = host.borrow_typed();
140 std::mem::take(applier_ref.slots())
141 };
142 let slots = Rc::new(RefCell::new(slots));
143
144 Self {
145 target,
146 host,
147 slots,
148 }
149 }
150
151 fn host(&self) -> Rc<ConcreteApplierHost<MemoryApplier>> {
153 Rc::clone(&self.host)
154 }
155
156 fn slots_handle(&self) -> Rc<RefCell<SlotTable>> {
159 Rc::clone(&self.slots)
160 }
161}
162
163impl Drop for ApplierSlotGuard<'_> {
164 fn drop(&mut self) {
165 {
169 let mut applier_ref = self.host.borrow_typed();
170 *applier_ref.slots() = std::mem::take(&mut *self.slots.borrow_mut());
171 }
172
173 {
175 let mut applier_ref = self.host.borrow_typed();
176 let original_applier = std::mem::take(&mut *applier_ref);
177 let _ = std::mem::replace(self.target, original_applier);
178 }
179 }
181}
182
183struct ModifierChainMeasurement {
185 result: MeasureResult,
186 content_offset: Point,
188 offset: Point,
190}
191
192type LayoutModifierNodeData = (
193 usize,
194 Rc<RefCell<Box<dyn cranpose_foundation::ModifierNode>>>,
195);
196
197struct ScratchVecPool<T> {
198 available: Vec<Vec<T>>,
199}
200
201impl<T> ScratchVecPool<T> {
202 fn acquire(&mut self) -> Vec<T> {
203 self.available.pop().unwrap_or_default()
204 }
205
206 fn release(&mut self, mut values: Vec<T>) {
207 values.clear();
208 self.available.push(values);
209 }
210
211 #[cfg(test)]
212 fn available_count(&self) -> usize {
213 self.available.len()
214 }
215}
216
217impl<T> Default for ScratchVecPool<T> {
218 fn default() -> Self {
219 Self {
220 available: Vec::new(),
221 }
222 }
223}
224
225#[derive(Clone, Debug, PartialEq, Eq)]
227pub struct SemanticsCallback {
228 node_id: NodeId,
229}
230
231impl SemanticsCallback {
232 pub fn new(node_id: NodeId) -> Self {
233 Self { node_id }
234 }
235
236 pub fn node_id(&self) -> NodeId {
237 self.node_id
238 }
239}
240
241#[derive(Clone, Debug, PartialEq, Eq)]
243pub enum SemanticsAction {
244 Click { handler: SemanticsCallback },
245}
246
247#[derive(Clone, Debug, PartialEq, Eq)]
250pub enum SemanticsRole {
251 Layout,
253 Subcompose,
255 Text { value: String },
257 Spacer,
259 Button,
261 Unknown,
263}
264
265#[derive(Clone, Debug, PartialEq, Eq)]
267pub struct SemanticsNode {
268 pub node_id: NodeId,
269 pub role: SemanticsRole,
270 pub actions: Vec<SemanticsAction>,
271 pub children: Vec<SemanticsNode>,
272 pub description: Option<String>,
273}
274
275impl SemanticsNode {
276 fn new(
277 node_id: NodeId,
278 role: SemanticsRole,
279 actions: Vec<SemanticsAction>,
280 children: Vec<SemanticsNode>,
281 description: Option<String>,
282 ) -> Self {
283 Self {
284 node_id,
285 role,
286 actions,
287 children,
288 description,
289 }
290 }
291}
292
293#[derive(Clone, Debug, PartialEq, Eq)]
295pub struct SemanticsTree {
296 root: SemanticsNode,
297}
298
299impl SemanticsTree {
300 fn new(root: SemanticsNode) -> Self {
301 Self { root }
302 }
303
304 pub fn root(&self) -> &SemanticsNode {
305 &self.root
306 }
307}
308
309#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
310pub struct LayoutAllocationDebugStats {
311 pub layout_box_count: usize,
312 pub layout_box_child_count: usize,
313 pub layout_box_child_capacity: usize,
314 pub layout_box_heap_bytes: usize,
315 pub modifier_slice_count: usize,
316 pub modifier_slice_heap_bytes: usize,
317 pub modifier_draw_command_count: usize,
318 pub modifier_draw_command_capacity: usize,
319 pub modifier_pointer_input_count: usize,
320 pub modifier_pointer_input_capacity: usize,
321 pub modifier_click_handler_count: usize,
322 pub modifier_click_handler_capacity: usize,
323 pub modifier_text_content_count: usize,
324 pub modifier_text_style_count: usize,
325 pub modifier_text_layout_options_count: usize,
326 pub modifier_prepared_text_layout_count: usize,
327 pub modifier_graphics_layer_count: usize,
328 pub modifier_graphics_layer_resolver_count: usize,
329 pub semantics_node_count: usize,
330 pub semantics_action_count: usize,
331 pub semantics_action_capacity: usize,
332 pub semantics_child_count: usize,
333 pub semantics_child_capacity: usize,
334 pub semantics_description_count: usize,
335 pub semantics_description_bytes: usize,
336 pub semantics_text_role_bytes: usize,
337 pub semantics_heap_bytes: usize,
338}
339
340impl LayoutAllocationDebugStats {
341 fn add_modifier_slice(&mut self, stats: ModifierNodeSlicesDebugStats) {
342 self.modifier_slice_count += 1;
343 self.modifier_slice_heap_bytes += stats.heap_bytes;
344 self.modifier_draw_command_count += stats.draw_command_count;
345 self.modifier_draw_command_capacity += stats.draw_command_capacity;
346 self.modifier_pointer_input_count += stats.pointer_input_count;
347 self.modifier_pointer_input_capacity += stats.pointer_input_capacity;
348 self.modifier_click_handler_count += stats.click_handler_count;
349 self.modifier_click_handler_capacity += stats.click_handler_capacity;
350 self.modifier_text_content_count += usize::from(stats.has_text_content);
351 self.modifier_text_style_count += usize::from(stats.has_text_style);
352 self.modifier_text_layout_options_count += usize::from(stats.has_text_layout_options);
353 self.modifier_prepared_text_layout_count += usize::from(stats.has_prepared_text_layout);
354 self.modifier_graphics_layer_count += usize::from(stats.has_graphics_layer);
355 self.modifier_graphics_layer_resolver_count +=
356 usize::from(stats.has_graphics_layer_resolver);
357 }
358}
359
360#[derive(Debug, Clone)]
362pub struct LayoutTree {
363 root: LayoutBox,
364}
365
366impl LayoutTree {
367 pub fn new(root: LayoutBox) -> Self {
368 Self { root }
369 }
370
371 pub fn root(&self) -> &LayoutBox {
372 &self.root
373 }
374
375 pub fn root_mut(&mut self) -> &mut LayoutBox {
376 &mut self.root
377 }
378
379 pub fn into_root(self) -> LayoutBox {
380 self.root
381 }
382
383 pub fn debug_allocation_stats(&self) -> LayoutAllocationDebugStats {
384 let mut stats = LayoutAllocationDebugStats::default();
385 record_layout_box_allocation_stats(&self.root, &mut stats);
386 stats
387 }
388}
389
390#[derive(Debug, Clone)]
392pub struct LayoutBox {
393 pub node_id: NodeId,
394 pub rect: GeometryRect,
395 pub content_offset: Point,
397 pub node_data: LayoutNodeData,
398 pub children: Vec<LayoutBox>,
399}
400
401impl LayoutBox {
402 pub fn new(
403 node_id: NodeId,
404 rect: GeometryRect,
405 content_offset: Point,
406 node_data: LayoutNodeData,
407 children: Vec<LayoutBox>,
408 ) -> Self {
409 Self {
410 node_id,
411 rect,
412 content_offset,
413 node_data,
414 children,
415 }
416 }
417}
418
419#[derive(Debug, Clone)]
421pub struct LayoutNodeData {
422 pub modifier: Modifier,
423 pub resolved_modifiers: ResolvedModifiers,
424 pub modifier_slices: Rc<ModifierNodeSlices>,
425 pub kind: LayoutNodeKind,
426}
427
428impl LayoutNodeData {
429 pub fn new(
430 modifier: Modifier,
431 resolved_modifiers: ResolvedModifiers,
432 modifier_slices: Rc<ModifierNodeSlices>,
433 kind: LayoutNodeKind,
434 ) -> Self {
435 Self {
436 modifier,
437 resolved_modifiers,
438 modifier_slices,
439 kind,
440 }
441 }
442
443 pub fn resolved_modifiers(&self) -> ResolvedModifiers {
444 self.resolved_modifiers
445 }
446
447 pub fn modifier_slices(&self) -> &ModifierNodeSlices {
448 &self.modifier_slices
449 }
450}
451
452#[derive(Clone)]
459pub enum LayoutNodeKind {
460 Layout,
461 Subcompose,
462 Spacer,
463 Button { on_click: Rc<RefCell<dyn FnMut()>> },
464 Unknown,
465}
466
467impl fmt::Debug for LayoutNodeKind {
468 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
469 match self {
470 LayoutNodeKind::Layout => f.write_str("Layout"),
471 LayoutNodeKind::Subcompose => f.write_str("Subcompose"),
472 LayoutNodeKind::Spacer => f.write_str("Spacer"),
473 LayoutNodeKind::Button { .. } => f.write_str("Button"),
474 LayoutNodeKind::Unknown => f.write_str("Unknown"),
475 }
476 }
477}
478
479pub trait LayoutEngine {
481 fn compute_layout(&mut self, root: NodeId, max_size: Size) -> Result<LayoutTree, NodeError>;
482}
483
484impl LayoutEngine for MemoryApplier {
485 fn compute_layout(&mut self, root: NodeId, max_size: Size) -> Result<LayoutTree, NodeError> {
486 let measurements = measure_layout(self, root, max_size)?;
487 Ok(measurements.into_layout_tree())
488 }
489}
490
491#[derive(Debug, Clone)]
493pub struct LayoutMeasurements {
494 root: Rc<MeasuredNode>,
495 semantics: Option<SemanticsTree>,
496 layout_tree: Option<LayoutTree>,
497}
498
499impl LayoutMeasurements {
500 fn new(
501 root: Rc<MeasuredNode>,
502 semantics: Option<SemanticsTree>,
503 layout_tree: Option<LayoutTree>,
504 ) -> Self {
505 Self {
506 root,
507 semantics,
508 layout_tree,
509 }
510 }
511
512 pub fn root_size(&self) -> Size {
514 self.root.size
515 }
516
517 pub fn semantics_tree(&self) -> Option<&SemanticsTree> {
518 self.semantics.as_ref()
519 }
520
521 pub fn debug_allocation_stats(&self) -> LayoutAllocationDebugStats {
522 let mut stats = self
523 .layout_tree
524 .as_ref()
525 .map(LayoutTree::debug_allocation_stats)
526 .unwrap_or_default();
527 if let Some(semantics) = &self.semantics {
528 record_semantics_allocation_stats(semantics.root(), &mut stats);
529 }
530 stats
531 }
532
533 pub fn into_layout_tree(self) -> LayoutTree {
535 self.layout_tree
536 .expect("layout tree was not built for these measurements")
537 }
538
539 pub fn layout_tree(&self) -> LayoutTree {
541 self.layout_tree
542 .clone()
543 .expect("layout tree was not built for these measurements")
544 }
545}
546
547pub fn build_semantics_tree_from_layout_tree(layout_tree: &LayoutTree) -> SemanticsTree {
552 SemanticsTree::new(build_semantics_node_from_layout_box(layout_tree.root()))
553}
554
555pub fn build_layout_tree_from_applier(
561 applier: &mut MemoryApplier,
562 root: NodeId,
563) -> Result<Option<LayoutTree>, NodeError> {
564 fn snapshot(
565 applier: &mut MemoryApplier,
566 node_id: NodeId,
567 ) -> Result<Option<(crate::widgets::nodes::layout_node::LayoutState, Vec<NodeId>)>, NodeError>
568 {
569 match applier.with_node::<LayoutNode, _>(node_id, |node| {
570 (node.layout_state(), node.children.clone())
571 }) {
572 Ok(snapshot) => return Ok(Some(snapshot)),
573 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {}
574 Err(err) => return Err(err),
575 }
576
577 match applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
578 (node.layout_state(), node.active_children())
579 }) {
580 Ok(snapshot) => Ok(Some(snapshot)),
581 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => Ok(None),
582 Err(err) => Err(err),
583 }
584 }
585
586 fn place(
587 applier: &mut MemoryApplier,
588 node_id: NodeId,
589 parent_content_origin: Point,
590 ) -> Result<Option<LayoutBox>, NodeError> {
591 let Some((state, child_ids)) = snapshot(applier, node_id)? else {
592 return Ok(None);
593 };
594 if !state.is_placed {
595 return Ok(None);
596 }
597
598 let top_left = Point {
599 x: parent_content_origin.x + state.position.x,
600 y: parent_content_origin.y + state.position.y,
601 };
602 let rect = GeometryRect {
603 x: top_left.x,
604 y: top_left.y,
605 width: state.size.width,
606 height: state.size.height,
607 };
608 let info = runtime_metadata_for(applier, node_id)?;
609 let kind = layout_kind_from_metadata(node_id, &info);
610 let RuntimeNodeMetadata {
611 modifier,
612 resolved_modifiers,
613 modifier_slices,
614 ..
615 } = info;
616 let data = LayoutNodeData::new(modifier, resolved_modifiers, modifier_slices, kind);
617 let child_origin = Point {
618 x: top_left.x + state.content_offset.x,
619 y: top_left.y + state.content_offset.y,
620 };
621 let mut children = Vec::with_capacity(child_ids.len());
622 for child_id in child_ids {
623 if let Some(child) = place(applier, child_id, child_origin)? {
624 children.push(child);
625 }
626 }
627
628 Ok(Some(LayoutBox::new(
629 node_id,
630 rect,
631 state.content_offset,
632 data,
633 children,
634 )))
635 }
636
637 place(applier, root, Point::default()).map(|root| root.map(LayoutTree::new))
638}
639
640pub fn build_semantics_tree_from_applier(
646 applier: &mut MemoryApplier,
647 root: NodeId,
648) -> Result<Option<SemanticsTree>, NodeError> {
649 fn node(
650 applier: &mut MemoryApplier,
651 node_id: NodeId,
652 ) -> Result<Option<SemanticsNode>, NodeError> {
653 match applier.with_node::<LayoutNode, _>(node_id, |layout| {
654 let state = layout.layout_state();
655 if !state.is_placed {
656 return None;
657 }
658 let role = role_from_modifier_slices(&layout.modifier_slices_snapshot());
659 let config = layout.semantics_configuration();
660 let children = layout.children.clone();
661 layout.clear_needs_semantics();
662 Some((role, config, children))
663 }) {
664 Ok(Some((role, config, child_ids))) => {
665 let mut children = Vec::with_capacity(child_ids.len());
666 for child_id in child_ids {
667 if let Some(child) = node(applier, child_id)? {
668 children.push(child);
669 }
670 }
671 return Ok(Some(semantics_node_from_parts(
672 node_id, role, config, children,
673 )));
674 }
675 Ok(None) => return Ok(None),
676 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {}
677 Err(err) => return Err(err),
678 }
679
680 match applier.with_node::<SubcomposeLayoutNode, _>(node_id, |subcompose| {
681 let state = subcompose.layout_state();
682 if !state.is_placed {
683 return None;
684 }
685 let config = collect_semantics_from_modifier(&subcompose.modifier());
686 let children = subcompose.active_children();
687 subcompose.clear_needs_semantics();
688 Some((config, children))
689 }) {
690 Ok(Some((config, child_ids))) => {
691 let mut children = Vec::with_capacity(child_ids.len());
692 for child_id in child_ids {
693 if let Some(child) = node(applier, child_id)? {
694 children.push(child);
695 }
696 }
697 Ok(Some(semantics_node_from_parts(
698 node_id,
699 SemanticsRole::Subcompose,
700 config,
701 children,
702 )))
703 }
704 Ok(None) | Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {
705 Ok(None)
706 }
707 Err(err) => Err(err),
708 }
709 }
710
711 node(applier, root).map(|root| root.map(SemanticsTree::new))
712}
713
714#[derive(Clone, Copy, Debug, PartialEq, Eq)]
715pub struct MeasureLayoutOptions {
716 pub collect_semantics: bool,
717 pub build_layout_tree: bool,
718}
719
720impl Default for MeasureLayoutOptions {
721 fn default() -> Self {
722 Self {
723 collect_semantics: true,
724 build_layout_tree: true,
725 }
726 }
727}
728
729pub fn tree_needs_layout(applier: &mut dyn Applier, root: NodeId) -> Result<bool, NodeError> {
737 Ok(applier.get_mut(root)?.needs_layout())
738}
739
740pub fn tree_needs_semantics(applier: &mut dyn Applier, root: NodeId) -> Result<bool, NodeError> {
746 Ok(applier.get_mut(root)?.needs_semantics())
747}
748
749#[cfg(test)]
751pub(crate) fn bubble_layout_dirty(applier: &mut MemoryApplier, node_id: NodeId) {
752 cranpose_core::bubble_layout_dirty(applier as &mut dyn Applier, node_id);
753}
754
755pub fn measure_layout(
757 applier: &mut MemoryApplier,
758 root: NodeId,
759 max_size: Size,
760) -> Result<LayoutMeasurements, NodeError> {
761 measure_layout_with_options(applier, root, max_size, MeasureLayoutOptions::default())
762}
763
764pub fn measure_layout_with_options(
765 applier: &mut MemoryApplier,
766 root: NodeId,
767 max_size: Size,
768 options: MeasureLayoutOptions,
769) -> Result<LayoutMeasurements, NodeError> {
770 process_pending_layout_repasses(applier, root)?;
771
772 let constraints = Constraints {
773 min_width: 0.0,
774 max_width: max_size.width,
775 min_height: 0.0,
776 max_height: max_size.height,
777 };
778
779 let (needs_remeasure, _needs_semantics, cached_epoch) = match applier
790 .with_node::<LayoutNode, _>(root, |node| {
791 (
792 node.needs_measure(), node.needs_semantics(),
794 node.cache_handles().epoch(),
795 )
796 }) {
797 Ok(tuple) => tuple,
798 Err(NodeError::TypeMismatch { .. }) => {
799 let node = applier.get_mut(root)?;
800 let measure_dirty = node.needs_measure();
804 let semantics_dirty = node.needs_semantics();
805 (measure_dirty, semantics_dirty, 0)
806 }
807 Err(err) => return Err(err),
808 };
809
810 let epoch = if needs_remeasure {
811 NEXT_CACHE_EPOCH.fetch_add(1, Ordering::Relaxed)
812 } else if cached_epoch != 0 {
813 cached_epoch
814 } else {
815 NEXT_CACHE_EPOCH.load(Ordering::Relaxed)
817 };
818
819 let guard = ApplierSlotGuard::new(applier);
827 let applier_host = guard.host();
828 let slots_handle = guard.slots_handle();
829
830 let mut builder =
833 LayoutBuilder::new_with_epoch(Rc::clone(&applier_host), epoch, Rc::clone(&slots_handle));
834
835 let measured = builder.measure_node(root, normalize_constraints(constraints))?;
840
841 if let Ok(mut applier) = applier_host.try_borrow_typed() {
845 if applier
846 .with_node::<LayoutNode, _>(root, |node| {
847 node.set_position(Point::default());
848 })
849 .is_err()
850 {
851 let _ = applier.with_node::<SubcomposeLayoutNode, _>(root, |node| {
852 node.set_position(Point::default());
853 });
854 }
855 }
856
857 let (layout_tree, semantics) = {
858 let mut applier_ref = applier_host.borrow_typed();
859 let layout_tree = if options.build_layout_tree {
860 Some(build_layout_tree(&mut applier_ref, &measured)?)
861 } else {
862 None
863 };
864 let semantics = if options.collect_semantics {
865 let semantics_tree = if let Some(layout_tree) = layout_tree.as_ref() {
866 clear_semantics_dirty_flags(&mut applier_ref, &measured)?;
867 build_semantics_tree_from_layout_tree(layout_tree)
868 } else {
869 build_semantics_tree_from_live_nodes(&mut applier_ref, &measured)?
870 };
871 Some(semantics_tree)
872 } else {
873 None
874 };
875 (layout_tree, semantics)
876 };
877
878 drop(builder);
881
882 Ok(LayoutMeasurements::new(measured, semantics, layout_tree))
886}
887
888fn process_pending_layout_repasses(
889 applier: &mut MemoryApplier,
890 root: NodeId,
891) -> Result<(), NodeError> {
892 let repass_nodes = crate::take_layout_repass_nodes();
893 if repass_nodes.is_empty() {
894 return Ok(());
895 }
896 for node_id in repass_nodes {
897 cranpose_core::bubble_layout_dirty(applier as &mut dyn Applier, node_id);
898 }
899 applier.get_mut(root)?.mark_needs_layout();
900 Ok(())
901}
902
903struct LayoutBuilder {
904 state: Rc<RefCell<LayoutBuilderState>>,
905}
906
907impl LayoutBuilder {
908 fn new_with_epoch(
909 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
910 epoch: u64,
911 slots: Rc<RefCell<SlotTable>>,
912 ) -> Self {
913 Self {
914 state: Rc::new(RefCell::new(LayoutBuilderState::new_with_epoch(
915 applier, epoch, slots,
916 ))),
917 }
918 }
919
920 fn measure_node(
921 &mut self,
922 node_id: NodeId,
923 constraints: Constraints,
924 ) -> Result<Rc<MeasuredNode>, NodeError> {
925 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
926 }
927
928 fn set_runtime_handle(&mut self, handle: Option<RuntimeHandle>) {
929 self.state.borrow_mut().runtime_handle = handle;
930 }
931}
932
933struct LayoutBuilderState {
934 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
935 runtime_handle: Option<RuntimeHandle>,
936 slots: Rc<RefCell<SlotTable>>,
939 cache_epoch: u64,
940 tmp_measurables: ScratchVecPool<Box<dyn Measurable>>,
941 tmp_records: ScratchVecPool<(NodeId, ChildRecord)>,
942 tmp_child_ids: ScratchVecPool<NodeId>,
943 tmp_layout_node_data: ScratchVecPool<LayoutModifierNodeData>,
944}
945
946impl LayoutBuilderState {
947 fn new_with_epoch(
948 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
949 epoch: u64,
950 slots: Rc<RefCell<SlotTable>>,
951 ) -> Self {
952 let runtime_handle = applier.borrow_typed().runtime_handle();
953
954 Self {
955 applier,
956 runtime_handle,
957 slots,
958 cache_epoch: epoch,
959 tmp_measurables: ScratchVecPool::default(),
960 tmp_records: ScratchVecPool::default(),
961 tmp_child_ids: ScratchVecPool::default(),
962 tmp_layout_node_data: ScratchVecPool::default(),
963 }
964 }
965
966 fn try_with_applier_result<R>(
967 state_rc: &Rc<RefCell<Self>>,
968 f: impl FnOnce(&mut MemoryApplier) -> Result<R, NodeError>,
969 ) -> Option<Result<R, NodeError>> {
970 let host = {
971 let state = state_rc.borrow();
972 Rc::clone(&state.applier)
973 };
974
975 let Ok(mut applier) = host.try_borrow_typed() else {
977 return None;
978 };
979
980 Some(f(&mut applier))
981 }
982
983 fn with_applier_result<R>(
984 state_rc: &Rc<RefCell<Self>>,
985 f: impl FnOnce(&mut MemoryApplier) -> Result<R, NodeError>,
986 ) -> Result<R, NodeError> {
987 Self::try_with_applier_result(state_rc, f).unwrap_or_else(|| {
988 Err(NodeError::MissingContext {
989 id: NodeId::default(),
990 reason: "applier already borrowed",
991 })
992 })
993 }
994
995 fn clear_node_placed(state_rc: &Rc<RefCell<Self>>, node_id: NodeId) {
998 let host = {
999 let state = state_rc.borrow();
1000 Rc::clone(&state.applier)
1001 };
1002 let Ok(mut applier) = host.try_borrow_typed() else {
1003 return;
1004 };
1005 if applier
1007 .with_node::<LayoutNode, _>(node_id, |node| {
1008 node.clear_placed();
1009 })
1010 .is_err()
1011 {
1012 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1013 node.clear_placed();
1014 });
1015 }
1016 }
1017
1018 fn measure_node(
1019 state_rc: Rc<RefCell<Self>>,
1020 node_id: NodeId,
1021 constraints: Constraints,
1022 ) -> Result<Rc<MeasuredNode>, NodeError> {
1023 Self::clear_node_placed(&state_rc, node_id);
1027
1028 if let Some(subcompose) =
1030 Self::try_measure_subcompose(Rc::clone(&state_rc), node_id, constraints)?
1031 {
1032 return Ok(subcompose);
1033 }
1034
1035 if let Some(result) = Self::try_with_applier_result(&state_rc, |applier| {
1037 match applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1038 LayoutNodeSnapshot::from_layout_node(layout_node)
1039 }) {
1040 Ok(snapshot) => Ok(Some(snapshot)),
1041 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => Ok(None),
1042 Err(err) => Err(err),
1043 }
1044 }) {
1045 if let Some(snapshot) = result? {
1047 return Self::measure_layout_node(
1048 Rc::clone(&state_rc),
1049 node_id,
1050 snapshot,
1051 constraints,
1052 );
1053 }
1054 }
1055 Ok(Rc::new(MeasuredNode::new(
1060 node_id,
1061 Size::default(),
1062 Point { x: 0.0, y: 0.0 },
1063 Point::default(), Vec::new(),
1065 )))
1066 }
1067
1068 fn try_measure_subcompose(
1069 state_rc: Rc<RefCell<Self>>,
1070 node_id: NodeId,
1071 constraints: Constraints,
1072 ) -> Result<Option<Rc<MeasuredNode>>, NodeError> {
1073 let applier_host = {
1074 let state = state_rc.borrow();
1075 Rc::clone(&state.applier)
1076 };
1077
1078 let (node_handle, resolved_modifiers) = {
1079 let Ok(mut applier) = applier_host.try_borrow_typed() else {
1081 return Ok(None);
1082 };
1083 let node = match applier.get_mut(node_id) {
1084 Ok(node) => node,
1085 Err(NodeError::Missing { .. }) => return Ok(None),
1086 Err(err) => return Err(err),
1087 };
1088 let any = node.as_any_mut();
1089 if let Some(subcompose) =
1090 any.downcast_mut::<crate::subcompose_layout::SubcomposeLayoutNode>()
1091 {
1092 let handle = subcompose.handle();
1093 let resolved_modifiers = handle.resolved_modifiers();
1094 (handle, resolved_modifiers)
1095 } else {
1096 return Ok(None);
1097 }
1098 };
1099
1100 let runtime_handle = {
1101 let mut state = state_rc.borrow_mut();
1102 if state.runtime_handle.is_none() {
1103 if let Ok(applier) = applier_host.try_borrow_typed() {
1105 state.runtime_handle = applier.runtime_handle();
1106 }
1107 }
1108 state
1109 .runtime_handle
1110 .clone()
1111 .ok_or(NodeError::MissingContext {
1112 id: node_id,
1113 reason: "runtime handle required for subcomposition",
1114 })?
1115 };
1116
1117 let props = resolved_modifiers.layout_properties();
1118 let padding = resolved_modifiers.padding();
1119 let offset = resolved_modifiers.offset();
1120 let mut inner_constraints = normalize_constraints(subtract_padding(constraints, padding));
1121
1122 if let DimensionConstraint::Points(width) = props.width() {
1123 let constrained_width = width - padding.horizontal_sum();
1124 inner_constraints.max_width = inner_constraints.max_width.min(constrained_width);
1125 inner_constraints.min_width = inner_constraints.min_width.min(constrained_width);
1126 }
1127 if let DimensionConstraint::Points(height) = props.height() {
1128 let constrained_height = height - padding.vertical_sum();
1129 inner_constraints.max_height = inner_constraints.max_height.min(constrained_height);
1130 inner_constraints.min_height = inner_constraints.min_height.min(constrained_height);
1131 }
1132
1133 let mut slots_guard = SlotsGuard::take(Rc::clone(&state_rc));
1134 let slots_host = slots_guard.host();
1135 let applier_host_dyn: Rc<dyn ApplierHost> = applier_host.clone();
1136 let observer = SnapshotStateObserver::new(|callback| callback());
1137 let composer = Composer::new(
1138 Rc::clone(&slots_host),
1139 applier_host_dyn,
1140 runtime_handle.clone(),
1141 observer,
1142 Some(node_id),
1143 );
1144 composer.enter_phase(Phase::Measure);
1145
1146 let state_rc_clone = Rc::clone(&state_rc);
1147 let measure_error = RefCell::new(None);
1148 let state_rc_for_subcompose = Rc::clone(&state_rc_clone);
1149 let error_for_subcompose = &measure_error;
1150 let measured_children: Rc<RefCell<HashMap<NodeId, Rc<MeasuredNode>>>> =
1151 Rc::new(RefCell::new(HashMap::default()));
1152 let measured_children_for_subcompose = Rc::clone(&measured_children);
1153
1154 let measure_result = node_handle.measure(
1155 &composer,
1156 node_id,
1157 inner_constraints,
1158 Box::new(
1159 move |child_id: NodeId, child_constraints: Constraints| -> Size {
1160 match Self::measure_node(
1161 Rc::clone(&state_rc_for_subcompose),
1162 child_id,
1163 child_constraints,
1164 ) {
1165 Ok(measured) => {
1166 measured_children_for_subcompose
1167 .borrow_mut()
1168 .insert(child_id, Rc::clone(&measured));
1169 measured.size
1170 }
1171 Err(err) => {
1172 let mut slot = error_for_subcompose.borrow_mut();
1173 if slot.is_none() {
1174 *slot = Some(err);
1175 }
1176 Size::default()
1177 }
1178 }
1179 },
1180 ),
1181 &measure_error,
1182 )?;
1183 drop(composer);
1184 slots_guard.restore(slots_host.into_table()?);
1185
1186 if let Some(err) = measure_error.borrow_mut().take() {
1187 return Err(err);
1188 }
1189
1190 let mut width = measure_result.size.width + padding.horizontal_sum();
1194 let mut height = measure_result.size.height + padding.vertical_sum();
1195
1196 width = resolve_dimension(
1197 width,
1198 props.width(),
1199 props.min_width(),
1200 props.max_width(),
1201 constraints.min_width,
1202 constraints.max_width,
1203 );
1204 height = resolve_dimension(
1205 height,
1206 props.height(),
1207 props.min_height(),
1208 props.max_height(),
1209 constraints.min_height,
1210 constraints.max_height,
1211 );
1212
1213 let mut children = Vec::with_capacity(measure_result.placements.len());
1214 let mut measured_children_by_id = measured_children.borrow_mut();
1215
1216 if let Ok(mut applier) = applier_host.try_borrow_typed() {
1218 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |parent_node| {
1219 parent_node.set_measured_size(Size { width, height });
1220 parent_node.clear_needs_measure();
1221 parent_node.clear_needs_layout();
1222 });
1223 }
1224
1225 for placement in measure_result.placements {
1226 let child = if let Some(measured) = measured_children_by_id.remove(&placement.node_id) {
1227 measured
1228 } else {
1229 Self::measure_node(Rc::clone(&state_rc), placement.node_id, inner_constraints)?
1235 };
1236 let position = Point {
1237 x: padding.left + placement.x,
1238 y: padding.top + placement.y,
1239 };
1240
1241 if let Ok(mut applier) = applier_host.try_borrow_typed() {
1245 let _ = applier.with_node::<LayoutNode, _>(placement.node_id, |node| {
1246 node.set_position(position);
1247 });
1248 }
1249
1250 children.push(MeasuredChild {
1251 node: child,
1252 offset: position,
1253 });
1254 }
1255
1256 node_handle.set_active_children(children.iter().map(|c| c.node.node_id));
1258
1259 Ok(Some(Rc::new(MeasuredNode::new(
1260 node_id,
1261 Size { width, height },
1262 offset,
1263 Point::default(), children,
1265 ))))
1266 }
1267 fn measure_through_modifier_chain(
1274 state_rc: &Rc<RefCell<Self>>,
1275 node_id: NodeId,
1276 measurables: &[Box<dyn Measurable>],
1277 measure_policy: &Rc<dyn MeasurePolicy>,
1278 constraints: Constraints,
1279 layout_node_data: &mut Vec<LayoutModifierNodeData>,
1280 ) -> ModifierChainMeasurement {
1281 use cranpose_foundation::NodeCapabilities;
1282
1283 layout_node_data.clear();
1285 let mut offset = Point::default();
1286
1287 {
1288 let state = state_rc.borrow();
1289 let mut applier = state.applier.borrow_typed();
1290
1291 let _ = applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1292 let chain_handle = layout_node.modifier_chain();
1293
1294 if !chain_handle.has_layout_nodes() {
1295 return;
1296 }
1297
1298 chain_handle.chain().for_each_forward_matching(
1300 NodeCapabilities::LAYOUT,
1301 |node_ref| {
1302 if let Some(index) = node_ref.entry_index() {
1303 if let Some(node_rc) = chain_handle.chain().get_node_rc(index) {
1305 layout_node_data.push((index, Rc::clone(&node_rc)));
1306 }
1307
1308 node_ref.with_node(|node| {
1312 if let Some(offset_node) =
1313 node.as_any()
1314 .downcast_ref::<crate::modifier_nodes::OffsetNode>()
1315 {
1316 let delta = offset_node.offset();
1317 offset.x += delta.x;
1318 offset.y += delta.y;
1319 }
1320 });
1321 }
1322 },
1323 );
1324 });
1325 }
1326
1327 if layout_node_data.is_empty() {
1330 let result = measure_policy.measure(measurables, constraints);
1331 let final_size = result.size;
1332 let placements = result.placements;
1333
1334 return ModifierChainMeasurement {
1335 result: MeasureResult {
1336 size: final_size,
1337 placements,
1338 },
1339 content_offset: Point::default(),
1340 offset,
1341 };
1342 }
1343
1344 let shared_context = Rc::new(RefCell::new(LayoutNodeContext::new()));
1349
1350 let policy_result = Rc::new(RefCell::new(None));
1352 let inner_coordinator: Box<dyn NodeCoordinator + '_> =
1353 Box::new(coordinator::InnerCoordinator::new(
1354 Rc::clone(measure_policy),
1355 measurables,
1356 Rc::clone(&policy_result),
1357 ));
1358
1359 let mut current_coordinator = inner_coordinator;
1361 while let Some((_, node_rc)) = layout_node_data.pop() {
1362 current_coordinator = Box::new(coordinator::LayoutModifierCoordinator::new(
1363 node_rc,
1364 current_coordinator,
1365 Rc::clone(&shared_context),
1366 ));
1367 }
1368
1369 let placeable = current_coordinator.measure(constraints);
1371 let final_size = Size {
1372 width: placeable.width(),
1373 height: placeable.height(),
1374 };
1375
1376 let content_offset = placeable.content_offset();
1378 let all_placement_offset = Point {
1379 x: content_offset.0,
1380 y: content_offset.1,
1381 };
1382
1383 let content_offset = Point {
1387 x: all_placement_offset.x - offset.x,
1388 y: all_placement_offset.y - offset.y,
1389 };
1390
1391 let placements = policy_result
1394 .borrow_mut()
1395 .take()
1396 .map(|result| result.placements)
1397 .unwrap_or_default();
1398
1399 let invalidations = shared_context.borrow_mut().take_invalidations();
1401 if !invalidations.is_empty() {
1402 Self::with_applier_result(state_rc, |applier| {
1404 applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1405 for kind in invalidations {
1406 match kind {
1407 InvalidationKind::Layout => layout_node.mark_needs_measure(),
1408 InvalidationKind::Draw => layout_node.mark_needs_redraw(),
1409 InvalidationKind::Semantics => layout_node.mark_needs_semantics(),
1410 InvalidationKind::PointerInput => layout_node.mark_needs_pointer_pass(),
1411 InvalidationKind::Focus => layout_node.mark_needs_focus_sync(),
1412 }
1413 }
1414 })
1415 })
1416 .ok();
1417 }
1418
1419 ModifierChainMeasurement {
1420 result: MeasureResult {
1421 size: final_size,
1422 placements,
1423 },
1424 content_offset,
1425 offset,
1426 }
1427 }
1428
1429 fn measure_layout_node(
1430 state_rc: Rc<RefCell<Self>>,
1431 node_id: NodeId,
1432 snapshot: LayoutNodeSnapshot,
1433 constraints: Constraints,
1434 ) -> Result<Rc<MeasuredNode>, NodeError> {
1435 let cache_epoch = {
1436 let state = state_rc.borrow();
1437 state.cache_epoch
1438 };
1439 let LayoutNodeSnapshot {
1440 measure_policy,
1441 cache,
1442 needs_layout,
1443 needs_measure,
1444 } = snapshot;
1445 cache.activate(cache_epoch);
1446
1447 if needs_measure {
1448 }
1450
1451 if !needs_measure && !needs_layout {
1455 if let Some(cached) = cache.get_measurement(constraints) {
1457 Self::with_applier_result(&state_rc, |applier| {
1459 applier.with_node::<LayoutNode, _>(node_id, |node| {
1460 node.clear_needs_measure();
1461 node.clear_needs_layout();
1462 })
1463 })
1464 .ok();
1465 return Ok(cached);
1466 }
1467 }
1468
1469 let (runtime_handle, applier_host) = {
1470 let state = state_rc.borrow();
1471 (state.runtime_handle.clone(), Rc::clone(&state.applier))
1472 };
1473
1474 let measure_handle = LayoutMeasureHandle::new(Rc::clone(&state_rc));
1475 let error = Rc::new(RefCell::new(None));
1476 let mut pools = VecPools::acquire(Rc::clone(&state_rc));
1477 let (measurables, records, child_ids, layout_node_data) = pools.parts();
1478
1479 applier_host
1480 .borrow_typed()
1481 .with_node::<LayoutNode, _>(node_id, |node| {
1482 child_ids.extend_from_slice(&node.children);
1483 })?;
1484
1485 for &child_id in child_ids.iter() {
1486 let measured = Rc::new(RefCell::new(None));
1487 let position = Rc::new(RefCell::new(None));
1488
1489 let data = {
1490 let mut applier = applier_host.borrow_typed();
1491 match applier.with_node::<LayoutNode, _>(child_id, |n| {
1492 (
1493 n.cache_handles(),
1494 n.layout_state_handle(),
1495 n.needs_layout(),
1496 n.needs_measure(),
1497 )
1498 }) {
1499 Ok((cache, state, needs_layout, needs_measure)) => {
1500 Some((cache, Some(state), needs_layout, needs_measure))
1501 }
1502 Err(NodeError::TypeMismatch { .. }) => {
1503 match applier.with_node::<SubcomposeLayoutNode, _>(child_id, |n| {
1504 (n.needs_layout(), n.needs_measure())
1505 }) {
1506 Ok((needs_layout, needs_measure)) => Some((
1507 LayoutNodeCacheHandles::default(),
1508 None,
1509 needs_layout,
1510 needs_measure,
1511 )),
1512 Err(NodeError::TypeMismatch { .. }) => None,
1513 Err(NodeError::Missing { .. }) => None,
1514 Err(err) => return Err(err),
1515 }
1516 }
1517 Err(NodeError::Missing { .. }) => None,
1518 Err(err) => return Err(err),
1519 }
1520 };
1521
1522 let Some((cache_handles, layout_state, needs_layout, needs_measure)) = data else {
1523 continue;
1524 };
1525
1526 cache_handles.activate(cache_epoch);
1527
1528 records.push((
1529 child_id,
1530 ChildRecord {
1531 measured: Rc::clone(&measured),
1532 last_position: Rc::clone(&position),
1533 },
1534 ));
1535 measurables.push(Box::new(LayoutChildMeasurable::new(
1536 Rc::clone(&applier_host),
1537 child_id,
1538 measured,
1539 position,
1540 Rc::clone(&error),
1541 runtime_handle.clone(),
1542 cache_handles,
1543 cache_epoch,
1544 needs_layout || needs_measure,
1545 Some(measure_handle.clone()),
1546 layout_state,
1547 )));
1548 }
1549
1550 let chain_constraints = constraints;
1551
1552 let modifier_chain_result = Self::measure_through_modifier_chain(
1553 &state_rc,
1554 node_id,
1555 measurables.as_slice(),
1556 &measure_policy,
1557 chain_constraints,
1558 layout_node_data,
1559 );
1560
1561 let (width, height, policy_result, content_offset, offset) = {
1563 let result = modifier_chain_result;
1564 if let Some(err) = error.borrow_mut().take() {
1567 return Err(err);
1568 }
1569
1570 (
1571 result.result.size.width,
1572 result.result.size.height,
1573 result.result,
1574 result.content_offset,
1575 result.offset,
1576 )
1577 };
1578
1579 let mut measured_children = Vec::with_capacity(records.len());
1580 for (child_id, record) in records.iter() {
1581 if let Some(measured) = record.measured.borrow_mut().take() {
1582 let base_position = policy_result
1583 .placements
1584 .iter()
1585 .find(|placement| placement.node_id == *child_id)
1586 .map(|placement| Point {
1587 x: placement.x,
1588 y: placement.y,
1589 })
1590 .or_else(|| record.last_position.borrow().as_ref().copied())
1591 .unwrap_or(Point { x: 0.0, y: 0.0 });
1592 let position = Point {
1594 x: content_offset.x + base_position.x,
1595 y: content_offset.y + base_position.y,
1596 };
1597 measured_children.push(MeasuredChild {
1598 node: measured,
1599 offset: position,
1600 });
1601 }
1602 }
1603
1604 let measured = Rc::new(MeasuredNode::new(
1605 node_id,
1606 Size { width, height },
1607 offset,
1608 content_offset,
1609 measured_children,
1610 ));
1611
1612 cache.store_measurement(constraints, Rc::clone(&measured));
1613
1614 Self::with_applier_result(&state_rc, |applier| {
1616 applier.with_node::<LayoutNode, _>(node_id, |node| {
1617 node.clear_needs_measure();
1618 node.clear_needs_layout();
1619 node.set_measured_size(Size { width, height });
1620 node.set_content_offset(content_offset);
1621 })
1622 })
1623 .ok();
1624
1625 Ok(measured)
1626 }
1627}
1628
1629struct LayoutNodeSnapshot {
1636 measure_policy: Rc<dyn MeasurePolicy>,
1637 cache: LayoutNodeCacheHandles,
1638 needs_layout: bool,
1639 needs_measure: bool,
1641}
1642
1643impl LayoutNodeSnapshot {
1644 fn from_layout_node(node: &LayoutNode) -> Self {
1645 Self {
1646 measure_policy: Rc::clone(&node.measure_policy),
1647 cache: node.cache_handles(),
1648 needs_layout: node.needs_layout(),
1649 needs_measure: node.needs_measure(),
1650 }
1651 }
1652}
1653
1654struct VecPools {
1656 state: Rc<RefCell<LayoutBuilderState>>,
1657 measurables: Option<Vec<Box<dyn Measurable>>>,
1658 records: Option<Vec<(NodeId, ChildRecord)>>,
1659 child_ids: Option<Vec<NodeId>>,
1660 layout_node_data: Option<Vec<LayoutModifierNodeData>>,
1661}
1662
1663impl VecPools {
1664 fn acquire(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1665 let (measurables, records, child_ids, layout_node_data) = {
1666 let mut state_mut = state.borrow_mut();
1667 (
1668 state_mut.tmp_measurables.acquire(),
1669 state_mut.tmp_records.acquire(),
1670 state_mut.tmp_child_ids.acquire(),
1671 state_mut.tmp_layout_node_data.acquire(),
1672 )
1673 };
1674 Self {
1675 state,
1676 measurables: Some(measurables),
1677 records: Some(records),
1678 child_ids: Some(child_ids),
1679 layout_node_data: Some(layout_node_data),
1680 }
1681 }
1682
1683 #[allow(clippy::type_complexity)] fn parts(
1685 &mut self,
1686 ) -> (
1687 &mut Vec<Box<dyn Measurable>>,
1688 &mut Vec<(NodeId, ChildRecord)>,
1689 &mut Vec<NodeId>,
1690 &mut Vec<LayoutModifierNodeData>,
1691 ) {
1692 let measurables = self
1693 .measurables
1694 .as_mut()
1695 .expect("measurables already returned");
1696 let records = self.records.as_mut().expect("records already returned");
1697 let child_ids = self.child_ids.as_mut().expect("child_ids already returned");
1698 let layout_node_data = self
1699 .layout_node_data
1700 .as_mut()
1701 .expect("layout_node_data already returned");
1702 (measurables, records, child_ids, layout_node_data)
1703 }
1704}
1705
1706impl Drop for VecPools {
1707 fn drop(&mut self) {
1708 let mut state = self.state.borrow_mut();
1709 if let Some(measurables) = self.measurables.take() {
1710 state.tmp_measurables.release(measurables);
1711 }
1712 if let Some(records) = self.records.take() {
1713 state.tmp_records.release(records);
1714 }
1715 if let Some(child_ids) = self.child_ids.take() {
1716 state.tmp_child_ids.release(child_ids);
1717 }
1718 if let Some(layout_node_data) = self.layout_node_data.take() {
1719 state.tmp_layout_node_data.release(layout_node_data);
1720 }
1721 }
1722}
1723
1724struct SlotsGuard {
1725 state: Rc<RefCell<LayoutBuilderState>>,
1726 slots: Option<SlotTable>,
1727}
1728
1729impl SlotsGuard {
1730 fn take(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1731 let slots = {
1732 let state_ref = state.borrow();
1733 let mut slots_ref = state_ref.slots.borrow_mut();
1734 std::mem::take(&mut *slots_ref)
1735 };
1736 Self {
1737 state,
1738 slots: Some(slots),
1739 }
1740 }
1741
1742 fn host(&mut self) -> Rc<SlotsHost> {
1743 let slots = self.slots.take().unwrap_or_default();
1744 Rc::new(SlotsHost::new(slots))
1745 }
1746
1747 fn restore(&mut self, slots: SlotTable) {
1748 debug_assert!(self.slots.is_none());
1749 self.slots = Some(slots);
1750 }
1751}
1752
1753impl Drop for SlotsGuard {
1754 fn drop(&mut self) {
1755 if let Some(slots) = self.slots.take() {
1756 let state_ref = self.state.borrow();
1757 *state_ref.slots.borrow_mut() = slots;
1758 }
1759 }
1760}
1761
1762#[derive(Clone)]
1763struct LayoutMeasureHandle {
1764 state: Rc<RefCell<LayoutBuilderState>>,
1765}
1766
1767impl LayoutMeasureHandle {
1768 fn new(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1769 Self { state }
1770 }
1771
1772 fn measure(
1773 &self,
1774 node_id: NodeId,
1775 constraints: Constraints,
1776 ) -> Result<Rc<MeasuredNode>, NodeError> {
1777 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
1778 }
1779}
1780
1781#[derive(Debug, Clone)]
1782pub(crate) struct MeasuredNode {
1783 node_id: NodeId,
1784 size: Size,
1785 offset: Point,
1787 content_offset: Point,
1789 children: Vec<MeasuredChild>,
1790}
1791
1792impl MeasuredNode {
1793 fn new(
1794 node_id: NodeId,
1795 size: Size,
1796 offset: Point,
1797 content_offset: Point,
1798 children: Vec<MeasuredChild>,
1799 ) -> Self {
1800 Self {
1801 node_id,
1802 size,
1803 offset,
1804 content_offset,
1805 children,
1806 }
1807 }
1808}
1809
1810#[derive(Debug, Clone)]
1811struct MeasuredChild {
1812 node: Rc<MeasuredNode>,
1813 offset: Point,
1814}
1815
1816struct ChildRecord {
1817 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1818 last_position: Rc<RefCell<Option<Point>>>,
1819}
1820
1821struct LayoutChildMeasurable {
1822 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1823 node_id: NodeId,
1824 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1825 last_position: Rc<RefCell<Option<Point>>>,
1826 error: Rc<RefCell<Option<NodeError>>>,
1827 runtime_handle: Option<RuntimeHandle>,
1828 cache: LayoutNodeCacheHandles,
1829 cache_epoch: u64,
1830 force_remeasure: Cell<bool>,
1831 measure_handle: Option<LayoutMeasureHandle>,
1832 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1833}
1834
1835impl LayoutChildMeasurable {
1836 #[allow(clippy::too_many_arguments)] fn new(
1838 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1839 node_id: NodeId,
1840 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1841 last_position: Rc<RefCell<Option<Point>>>,
1842 error: Rc<RefCell<Option<NodeError>>>,
1843 runtime_handle: Option<RuntimeHandle>,
1844 cache: LayoutNodeCacheHandles,
1845 cache_epoch: u64,
1846 force_remeasure: bool,
1847 measure_handle: Option<LayoutMeasureHandle>,
1848 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1849 ) -> Self {
1850 cache.activate(cache_epoch);
1851 Self {
1852 applier,
1853 node_id,
1854 measured,
1855 last_position,
1856 error,
1857 runtime_handle,
1858 cache,
1859 cache_epoch,
1860 force_remeasure: Cell::new(force_remeasure),
1861 measure_handle,
1862 layout_state,
1863 }
1864 }
1865
1866 fn record_error(&self, err: NodeError) {
1867 let mut slot = self.error.borrow_mut();
1868 if slot.is_none() {
1869 *slot = Some(err);
1870 }
1871 }
1872
1873 fn perform_measure(&self, constraints: Constraints) -> Result<Rc<MeasuredNode>, NodeError> {
1874 if let Some(handle) = &self.measure_handle {
1875 handle.measure(self.node_id, constraints)
1876 } else {
1877 measure_node_with_host(
1878 Rc::clone(&self.applier),
1879 self.runtime_handle.clone(),
1880 self.node_id,
1881 constraints,
1882 self.cache_epoch,
1883 )
1884 }
1885 }
1886
1887 fn intrinsic_measure(&self, constraints: Constraints) -> Option<Rc<MeasuredNode>> {
1888 self.cache.activate(self.cache_epoch);
1889 if !self.force_remeasure.get() {
1890 if let Some(cached) = self.cache.get_measurement(constraints) {
1891 return Some(cached);
1892 }
1893 }
1894
1895 match self.perform_measure(constraints) {
1896 Ok(measured) => {
1897 self.force_remeasure.set(false);
1898 self.cache
1899 .store_measurement(constraints, Rc::clone(&measured));
1900 Some(measured)
1901 }
1902 Err(err) => {
1903 self.record_error(err);
1904 None
1905 }
1906 }
1907 }
1908}
1909
1910impl Measurable for LayoutChildMeasurable {
1911 fn measure(&self, constraints: Constraints) -> Placeable {
1912 self.cache.activate(self.cache_epoch);
1913 let measured_size;
1914 if !self.force_remeasure.get() {
1915 if let Some(cached) = self.cache.get_measurement(constraints) {
1916 measured_size = cached.size;
1917 *self.measured.borrow_mut() = Some(Rc::clone(&cached));
1918 } else {
1919 match self.perform_measure(constraints) {
1920 Ok(measured) => {
1921 self.force_remeasure.set(false);
1922 measured_size = measured.size;
1923 self.cache
1924 .store_measurement(constraints, Rc::clone(&measured));
1925 *self.measured.borrow_mut() = Some(measured);
1926 }
1927 Err(err) => {
1928 self.record_error(err);
1929 self.measured.borrow_mut().take();
1930 measured_size = Size {
1931 width: 0.0,
1932 height: 0.0,
1933 };
1934 }
1935 }
1936 }
1937 } else {
1938 match self.perform_measure(constraints) {
1939 Ok(measured) => {
1940 self.force_remeasure.set(false);
1941 measured_size = measured.size;
1942 self.cache
1943 .store_measurement(constraints, Rc::clone(&measured));
1944 *self.measured.borrow_mut() = Some(measured);
1945 }
1946 Err(err) => {
1947 self.record_error(err);
1948 self.measured.borrow_mut().take();
1949 measured_size = Size {
1950 width: 0.0,
1951 height: 0.0,
1952 };
1953 }
1954 }
1955 }
1956
1957 if let Some(state) = &self.layout_state {
1960 let mut state = state.borrow_mut();
1961 state.size = measured_size;
1962 state.measurement_constraints = constraints;
1963 } else if let Ok(mut applier) = self.applier.try_borrow_typed() {
1964 let _ = applier.with_node::<LayoutNode, _>(self.node_id, |node| {
1965 node.set_measured_size(measured_size);
1966 node.set_measurement_constraints(constraints);
1967 });
1968 }
1969
1970 let applier = Rc::clone(&self.applier);
1972 let node_id = self.node_id;
1973 let measured = Rc::clone(&self.measured);
1974 let last_position = Rc::clone(&self.last_position);
1975 let layout_state = self.layout_state.clone();
1976
1977 let place_fn = Rc::new(move |x: f32, y: f32| {
1978 let internal_offset = measured
1980 .borrow()
1981 .as_ref()
1982 .map(|m| m.offset)
1983 .unwrap_or_default();
1984
1985 let position = Point {
1986 x: x + internal_offset.x,
1987 y: y + internal_offset.y,
1988 };
1989 *last_position.borrow_mut() = Some(position);
1990
1991 if let Some(state) = &layout_state {
1993 let mut state = state.borrow_mut();
1994 state.position = position;
1995 state.is_placed = true;
1996 } else if let Ok(mut applier) = applier.try_borrow_typed() {
1997 if applier
1998 .with_node::<LayoutNode, _>(node_id, |node| {
1999 node.set_position(position);
2000 })
2001 .is_err()
2002 {
2003 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
2004 node.set_position(position);
2005 });
2006 }
2007 }
2008 });
2009
2010 Placeable::with_place_fn(
2011 measured_size.width,
2012 measured_size.height,
2013 self.node_id,
2014 place_fn,
2015 )
2016 }
2017
2018 fn min_intrinsic_width(&self, height: f32) -> f32 {
2019 let kind = IntrinsicKind::MinWidth(height);
2020 self.cache.activate(self.cache_epoch);
2021 if !self.force_remeasure.get() {
2022 if let Some(value) = self.cache.get_intrinsic(&kind) {
2023 return value;
2024 }
2025 }
2026 let constraints = Constraints {
2027 min_width: 0.0,
2028 max_width: f32::INFINITY,
2029 min_height: height,
2030 max_height: height,
2031 };
2032 if let Some(node) = self.intrinsic_measure(constraints) {
2033 let value = node.size.width;
2034 self.cache.store_intrinsic(kind, value);
2035 value
2036 } else {
2037 0.0
2038 }
2039 }
2040
2041 fn max_intrinsic_width(&self, height: f32) -> f32 {
2042 let kind = IntrinsicKind::MaxWidth(height);
2043 self.cache.activate(self.cache_epoch);
2044 if !self.force_remeasure.get() {
2045 if let Some(value) = self.cache.get_intrinsic(&kind) {
2046 return value;
2047 }
2048 }
2049 let constraints = Constraints {
2050 min_width: 0.0,
2051 max_width: f32::INFINITY,
2052 min_height: 0.0,
2053 max_height: height,
2054 };
2055 if let Some(node) = self.intrinsic_measure(constraints) {
2056 let value = node.size.width;
2057 self.cache.store_intrinsic(kind, value);
2058 value
2059 } else {
2060 0.0
2061 }
2062 }
2063
2064 fn min_intrinsic_height(&self, width: f32) -> f32 {
2065 let kind = IntrinsicKind::MinHeight(width);
2066 self.cache.activate(self.cache_epoch);
2067 if !self.force_remeasure.get() {
2068 if let Some(value) = self.cache.get_intrinsic(&kind) {
2069 return value;
2070 }
2071 }
2072 let constraints = Constraints {
2073 min_width: width,
2074 max_width: width,
2075 min_height: 0.0,
2076 max_height: f32::INFINITY,
2077 };
2078 if let Some(node) = self.intrinsic_measure(constraints) {
2079 let value = node.size.height;
2080 self.cache.store_intrinsic(kind, value);
2081 value
2082 } else {
2083 0.0
2084 }
2085 }
2086
2087 fn max_intrinsic_height(&self, width: f32) -> f32 {
2088 let kind = IntrinsicKind::MaxHeight(width);
2089 self.cache.activate(self.cache_epoch);
2090 if !self.force_remeasure.get() {
2091 if let Some(value) = self.cache.get_intrinsic(&kind) {
2092 return value;
2093 }
2094 }
2095 let constraints = Constraints {
2096 min_width: 0.0,
2097 max_width: width,
2098 min_height: 0.0,
2099 max_height: f32::INFINITY,
2100 };
2101 if let Some(node) = self.intrinsic_measure(constraints) {
2102 let value = node.size.height;
2103 self.cache.store_intrinsic(kind, value);
2104 value
2105 } else {
2106 0.0
2107 }
2108 }
2109
2110 fn flex_parent_data(&self) -> Option<cranpose_ui_layout::FlexParentData> {
2111 let Ok(mut applier) = self.applier.try_borrow_typed() else {
2114 return None;
2115 };
2116
2117 applier
2118 .with_node::<LayoutNode, _>(self.node_id, |layout_node| {
2119 let props = layout_node.resolved_modifiers().layout_properties();
2120 props.weight().map(|weight_data| {
2121 cranpose_ui_layout::FlexParentData::new(weight_data.weight, weight_data.fill)
2122 })
2123 })
2124 .ok()
2125 .flatten()
2126 }
2127}
2128
2129fn measure_node_with_host(
2130 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
2131 runtime_handle: Option<RuntimeHandle>,
2132 node_id: NodeId,
2133 constraints: Constraints,
2134 epoch: u64,
2135) -> Result<Rc<MeasuredNode>, NodeError> {
2136 let runtime_handle = match runtime_handle {
2137 Some(handle) => Some(handle),
2138 None => applier.borrow_typed().runtime_handle(),
2139 };
2140 let mut builder =
2141 LayoutBuilder::new_with_epoch(applier, epoch, Rc::new(RefCell::new(SlotTable::default())));
2142 builder.set_runtime_handle(runtime_handle);
2143 builder.measure_node(node_id, constraints)
2144}
2145
2146#[derive(Clone)]
2147struct RuntimeNodeMetadata {
2148 modifier: Modifier,
2149 resolved_modifiers: ResolvedModifiers,
2150 modifier_slices: Rc<ModifierNodeSlices>,
2151 role: SemanticsRole,
2152 button_handler: Option<Rc<RefCell<dyn FnMut()>>>,
2153}
2154
2155impl Default for RuntimeNodeMetadata {
2156 fn default() -> Self {
2157 Self {
2158 modifier: Modifier::empty(),
2159 resolved_modifiers: ResolvedModifiers::default(),
2160 modifier_slices: Rc::default(),
2161 role: SemanticsRole::Unknown,
2162 button_handler: None,
2163 }
2164 }
2165}
2166
2167fn role_from_modifier_slices(modifier_slices: &ModifierNodeSlices) -> SemanticsRole {
2168 modifier_slices
2169 .text_content()
2170 .map(|text| SemanticsRole::Text {
2171 value: text.to_string(),
2172 })
2173 .unwrap_or(SemanticsRole::Layout)
2174}
2175
2176fn runtime_metadata_for(
2177 applier: &mut MemoryApplier,
2178 node_id: NodeId,
2179) -> Result<RuntimeNodeMetadata, NodeError> {
2180 if let Ok(meta) = applier.with_node::<LayoutNode, _>(node_id, |layout| {
2185 let modifier = layout.modifier.clone();
2186 let resolved_modifiers = layout.resolved_modifiers();
2187 let modifier_slices = layout.modifier_slices_snapshot();
2188 let role = role_from_modifier_slices(&modifier_slices);
2189
2190 RuntimeNodeMetadata {
2191 modifier,
2192 resolved_modifiers,
2193 modifier_slices,
2194 role,
2195 button_handler: None,
2196 }
2197 }) {
2198 return Ok(meta);
2199 }
2200
2201 if let Ok((modifier, resolved_modifiers, modifier_slices)) = applier
2203 .with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
2204 (
2205 node.modifier(),
2206 node.resolved_modifiers(),
2207 node.modifier_slices_snapshot(),
2208 )
2209 })
2210 {
2211 return Ok(RuntimeNodeMetadata {
2212 modifier,
2213 resolved_modifiers,
2214 modifier_slices,
2215 role: SemanticsRole::Subcompose,
2216 button_handler: None,
2217 });
2218 }
2219 Ok(RuntimeNodeMetadata::default())
2220}
2221
2222fn clear_semantics_dirty_flags(
2223 applier: &mut MemoryApplier,
2224 node: &MeasuredNode,
2225) -> Result<(), NodeError> {
2226 match applier.with_node::<LayoutNode, _>(node.node_id, |layout| {
2227 layout.clear_needs_semantics();
2228 }) {
2229 Ok(()) => {}
2230 Err(NodeError::Missing { .. }) => {}
2231 Err(NodeError::TypeMismatch { .. }) => {
2232 match applier.with_node::<SubcomposeLayoutNode, _>(node.node_id, |subcompose| {
2233 subcompose.clear_needs_semantics();
2234 }) {
2235 Ok(()) | Err(NodeError::Missing { .. }) | Err(NodeError::TypeMismatch { .. }) => {}
2236 Err(err) => return Err(err),
2237 }
2238 }
2239 Err(err) => return Err(err),
2240 }
2241
2242 for child in &node.children {
2243 clear_semantics_dirty_flags(applier, &child.node)?;
2244 }
2245
2246 Ok(())
2247}
2248
2249fn build_semantics_tree_from_live_nodes(
2250 applier: &mut MemoryApplier,
2251 node: &MeasuredNode,
2252) -> Result<SemanticsTree, NodeError> {
2253 Ok(SemanticsTree::new(build_semantics_node_from_live_nodes(
2254 applier, node,
2255 )?))
2256}
2257
2258fn semantics_node_from_parts(
2259 node_id: NodeId,
2260 mut role: SemanticsRole,
2261 config: Option<SemanticsConfiguration>,
2262 children: Vec<SemanticsNode>,
2263) -> SemanticsNode {
2264 let mut actions = Vec::new();
2265 let mut description = None;
2266
2267 if let Some(config) = config {
2268 if config.is_button {
2269 role = SemanticsRole::Button;
2270 }
2271 if config.is_clickable {
2272 actions.push(SemanticsAction::Click {
2273 handler: SemanticsCallback::new(node_id),
2274 });
2275 }
2276 description = config.content_description;
2277 }
2278
2279 SemanticsNode::new(node_id, role, actions, children, description)
2280}
2281
2282fn build_semantics_node_from_live_nodes(
2283 applier: &mut MemoryApplier,
2284 node: &MeasuredNode,
2285) -> Result<SemanticsNode, NodeError> {
2286 let (role, config) = match applier.with_node::<LayoutNode, _>(node.node_id, |layout| {
2287 let role = role_from_modifier_slices(&layout.modifier_slices_snapshot());
2288 let config = layout.semantics_configuration();
2289 layout.clear_needs_semantics();
2290 (role, config)
2291 }) {
2292 Ok(data) => data,
2293 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {
2294 match applier.with_node::<SubcomposeLayoutNode, _>(node.node_id, |subcompose| {
2295 subcompose.clear_needs_semantics();
2296 (
2297 SemanticsRole::Subcompose,
2298 collect_semantics_from_modifier(&subcompose.modifier()),
2299 )
2300 }) {
2301 Ok(data) => data,
2302 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {
2303 (SemanticsRole::Unknown, None)
2304 }
2305 Err(err) => return Err(err),
2306 }
2307 }
2308 Err(err) => return Err(err),
2309 };
2310
2311 let mut children = Vec::with_capacity(node.children.len());
2312 for child in &node.children {
2313 children.push(build_semantics_node_from_live_nodes(applier, &child.node)?);
2314 }
2315
2316 Ok(semantics_node_from_parts(
2317 node.node_id,
2318 role,
2319 config,
2320 children,
2321 ))
2322}
2323
2324fn record_semantics_allocation_stats(node: &SemanticsNode, stats: &mut LayoutAllocationDebugStats) {
2325 stats.semantics_node_count += 1;
2326 stats.semantics_action_count += node.actions.len();
2327 stats.semantics_action_capacity += node.actions.capacity();
2328 stats.semantics_child_count += node.children.len();
2329 stats.semantics_child_capacity += node.children.capacity();
2330 stats.semantics_heap_bytes += node.actions.capacity() * size_of::<SemanticsAction>();
2331 stats.semantics_heap_bytes += node.children.capacity() * size_of::<SemanticsNode>();
2332
2333 if let Some(description) = &node.description {
2334 stats.semantics_description_count += 1;
2335 stats.semantics_description_bytes += description.capacity();
2336 stats.semantics_heap_bytes += description.capacity();
2337 }
2338 if let SemanticsRole::Text { value } = &node.role {
2339 stats.semantics_text_role_bytes += value.capacity();
2340 stats.semantics_heap_bytes += value.capacity();
2341 }
2342
2343 for child in &node.children {
2344 record_semantics_allocation_stats(child, stats);
2345 }
2346}
2347
2348fn record_layout_box_allocation_stats(
2349 layout_box: &LayoutBox,
2350 stats: &mut LayoutAllocationDebugStats,
2351) {
2352 stats.layout_box_count += 1;
2353 stats.layout_box_child_count += layout_box.children.len();
2354 stats.layout_box_child_capacity += layout_box.children.capacity();
2355 stats.layout_box_heap_bytes += layout_box.children.capacity() * size_of::<LayoutBox>();
2356 stats.add_modifier_slice(layout_box.node_data.modifier_slices().debug_stats());
2357
2358 for child in &layout_box.children {
2359 record_layout_box_allocation_stats(child, stats);
2360 }
2361}
2362
2363fn build_layout_tree(
2364 applier: &mut MemoryApplier,
2365 node: &MeasuredNode,
2366) -> Result<LayoutTree, NodeError> {
2367 fn place(
2368 applier: &mut MemoryApplier,
2369 node: &MeasuredNode,
2370 origin: Point,
2371 ) -> Result<LayoutBox, NodeError> {
2372 let top_left = Point {
2374 x: origin.x + node.offset.x,
2375 y: origin.y + node.offset.y,
2376 };
2377 let rect = GeometryRect {
2378 x: top_left.x,
2379 y: top_left.y,
2380 width: node.size.width,
2381 height: node.size.height,
2382 };
2383 let info = runtime_metadata_for(applier, node.node_id)?;
2384 let kind = layout_kind_from_metadata(node.node_id, &info);
2385 let RuntimeNodeMetadata {
2386 modifier,
2387 resolved_modifiers,
2388 modifier_slices,
2389 ..
2390 } = info;
2391 let data = LayoutNodeData::new(modifier, resolved_modifiers, modifier_slices, kind);
2392 let mut children = Vec::with_capacity(node.children.len());
2393 for child in &node.children {
2394 let child_origin = Point {
2395 x: top_left.x + child.offset.x,
2396 y: top_left.y + child.offset.y,
2397 };
2398 children.push(place(applier, &child.node, child_origin)?);
2399 }
2400 Ok(LayoutBox::new(
2401 node.node_id,
2402 rect,
2403 node.content_offset,
2404 data,
2405 children,
2406 ))
2407 }
2408
2409 Ok(LayoutTree::new(place(
2410 applier,
2411 node,
2412 Point { x: 0.0, y: 0.0 },
2413 )?))
2414}
2415
2416fn semantics_role_from_layout_box(layout_box: &LayoutBox) -> SemanticsRole {
2417 match &layout_box.node_data.kind {
2418 LayoutNodeKind::Subcompose => SemanticsRole::Subcompose,
2419 LayoutNodeKind::Spacer => SemanticsRole::Spacer,
2420 LayoutNodeKind::Unknown => SemanticsRole::Unknown,
2421 LayoutNodeKind::Button { .. } => SemanticsRole::Button,
2422 LayoutNodeKind::Layout => layout_box
2423 .node_data
2424 .modifier_slices()
2425 .text_content()
2426 .map(|text| SemanticsRole::Text {
2427 value: text.to_string(),
2428 })
2429 .unwrap_or(SemanticsRole::Layout),
2430 }
2431}
2432
2433fn build_semantics_node_from_layout_box(layout_box: &LayoutBox) -> SemanticsNode {
2434 let children = layout_box
2435 .children
2436 .iter()
2437 .map(build_semantics_node_from_layout_box)
2438 .collect();
2439
2440 semantics_node_from_parts(
2441 layout_box.node_id,
2442 semantics_role_from_layout_box(layout_box),
2443 collect_semantics_from_modifier(&layout_box.node_data.modifier),
2444 children,
2445 )
2446}
2447
2448fn layout_kind_from_metadata(_node_id: NodeId, info: &RuntimeNodeMetadata) -> LayoutNodeKind {
2449 match &info.role {
2450 SemanticsRole::Layout => LayoutNodeKind::Layout,
2451 SemanticsRole::Subcompose => LayoutNodeKind::Subcompose,
2452 SemanticsRole::Text { .. } => {
2453 LayoutNodeKind::Layout
2457 }
2458 SemanticsRole::Spacer => LayoutNodeKind::Spacer,
2459 SemanticsRole::Button => {
2460 let handler = info
2461 .button_handler
2462 .as_ref()
2463 .cloned()
2464 .unwrap_or_else(|| Rc::new(RefCell::new(|| {})));
2465 LayoutNodeKind::Button { on_click: handler }
2466 }
2467 SemanticsRole::Unknown => LayoutNodeKind::Unknown,
2468 }
2469}
2470
2471fn subtract_padding(constraints: Constraints, padding: EdgeInsets) -> Constraints {
2472 let horizontal = padding.horizontal_sum();
2473 let vertical = padding.vertical_sum();
2474 let min_width = (constraints.min_width - horizontal).max(0.0);
2475 let mut max_width = constraints.max_width;
2476 if max_width.is_finite() {
2477 max_width = (max_width - horizontal).max(0.0);
2478 }
2479 let min_height = (constraints.min_height - vertical).max(0.0);
2480 let mut max_height = constraints.max_height;
2481 if max_height.is_finite() {
2482 max_height = (max_height - vertical).max(0.0);
2483 }
2484 normalize_constraints(Constraints {
2485 min_width,
2486 max_width,
2487 min_height,
2488 max_height,
2489 })
2490}
2491
2492#[cfg(test)]
2493pub(crate) fn align_horizontal(alignment: HorizontalAlignment, available: f32, child: f32) -> f32 {
2494 match alignment {
2495 HorizontalAlignment::Start => 0.0,
2496 HorizontalAlignment::CenterHorizontally => ((available - child) / 2.0).max(0.0),
2497 HorizontalAlignment::End => (available - child).max(0.0),
2498 }
2499}
2500
2501#[cfg(test)]
2502pub(crate) fn align_vertical(alignment: VerticalAlignment, available: f32, child: f32) -> f32 {
2503 match alignment {
2504 VerticalAlignment::Top => 0.0,
2505 VerticalAlignment::CenterVertically => ((available - child) / 2.0).max(0.0),
2506 VerticalAlignment::Bottom => (available - child).max(0.0),
2507 }
2508}
2509
2510fn resolve_dimension(
2511 base: f32,
2512 explicit: DimensionConstraint,
2513 min_override: Option<f32>,
2514 max_override: Option<f32>,
2515 min_limit: f32,
2516 max_limit: f32,
2517) -> f32 {
2518 let mut min_bound = min_limit;
2519 if let Some(min_value) = min_override {
2520 min_bound = min_bound.max(min_value);
2521 }
2522
2523 let mut max_bound = if max_limit.is_finite() {
2524 max_limit
2525 } else {
2526 max_override.unwrap_or(max_limit)
2527 };
2528 if let Some(max_value) = max_override {
2529 if max_bound.is_finite() {
2530 max_bound = max_bound.min(max_value);
2531 } else {
2532 max_bound = max_value;
2533 }
2534 }
2535 if max_bound < min_bound {
2536 max_bound = min_bound;
2537 }
2538
2539 let mut size = match explicit {
2540 DimensionConstraint::Points(points) => points,
2541 DimensionConstraint::Fraction(fraction) => {
2542 if max_limit.is_finite() {
2543 max_limit * fraction.clamp(0.0, 1.0)
2544 } else {
2545 base
2546 }
2547 }
2548 DimensionConstraint::Unspecified => base,
2549 DimensionConstraint::Intrinsic(_) => base,
2552 };
2553
2554 size = clamp_dimension(size, min_bound, max_bound);
2555 size = clamp_dimension(size, min_limit, max_limit);
2556 size.max(0.0)
2557}
2558
2559fn clamp_dimension(value: f32, min: f32, max: f32) -> f32 {
2560 let mut result = value.max(min);
2561 if max.is_finite() {
2562 result = result.min(max);
2563 }
2564 result
2565}
2566
2567fn normalize_constraints(mut constraints: Constraints) -> Constraints {
2568 if constraints.max_width < constraints.min_width {
2569 constraints.max_width = constraints.min_width;
2570 }
2571 if constraints.max_height < constraints.min_height {
2572 constraints.max_height = constraints.min_height;
2573 }
2574 constraints
2575}
2576
2577#[cfg(test)]
2578#[path = "tests/layout_tests.rs"]
2579mod tests;