1pub mod coordinator;
4pub mod core;
5pub mod policies;
6
7use cranpose_core::collections::map::Entry;
8use cranpose_core::collections::map::HashMap;
9use std::{
10 cell::RefCell,
11 fmt,
12 rc::Rc,
13 sync::atomic::{AtomicU64, Ordering},
14};
15
16use cranpose_core::{
17 Applier, ApplierHost, Composer, ConcreteApplierHost, MemoryApplier, NodeError, NodeId, Phase,
18 RuntimeHandle, SlotBackend, 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 Point, Rect as GeometryRect, ResolvedModifiers, Size,
29};
30
31use crate::subcompose_layout::SubcomposeLayoutNode;
32use crate::widgets::nodes::{IntrinsicKind, LayoutNode, LayoutNodeCacheHandles};
33use cranpose_foundation::InvalidationKind;
34use cranpose_foundation::ModifierNodeContext;
35use cranpose_foundation::{NodeCapabilities, SemanticsConfiguration};
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<SlotBackend>>,
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<SlotBackend>> {
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)]
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)]
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(Default)]
312pub struct SemanticsOwner {
313 configurations: RefCell<HashMap<NodeId, Option<SemanticsConfiguration>>>,
314}
315
316impl SemanticsOwner {
317 pub fn new() -> Self {
318 Self {
319 configurations: RefCell::new(HashMap::default()),
320 }
321 }
322
323 pub fn get_or_compute(
325 &self,
326 node_id: NodeId,
327 applier: &mut MemoryApplier,
328 ) -> Option<SemanticsConfiguration> {
329 if let Some(cached) = self.configurations.borrow().get(&node_id) {
331 return cached.clone();
332 }
333
334 let config = compute_semantics_for_node(applier, node_id);
336 self.configurations
337 .borrow_mut()
338 .insert(node_id, config.clone());
339 config
340 }
341}
342
343#[derive(Debug, Clone)]
345pub struct LayoutTree {
346 root: LayoutBox,
347}
348
349impl LayoutTree {
350 pub fn new(root: LayoutBox) -> Self {
351 Self { root }
352 }
353
354 pub fn root(&self) -> &LayoutBox {
355 &self.root
356 }
357
358 pub fn root_mut(&mut self) -> &mut LayoutBox {
359 &mut self.root
360 }
361
362 pub fn into_root(self) -> LayoutBox {
363 self.root
364 }
365}
366
367#[derive(Debug, Clone)]
369pub struct LayoutBox {
370 pub node_id: NodeId,
371 pub rect: GeometryRect,
372 pub content_offset: Point,
374 pub node_data: LayoutNodeData,
375 pub children: Vec<LayoutBox>,
376}
377
378impl LayoutBox {
379 pub fn new(
380 node_id: NodeId,
381 rect: GeometryRect,
382 content_offset: Point,
383 node_data: LayoutNodeData,
384 children: Vec<LayoutBox>,
385 ) -> Self {
386 Self {
387 node_id,
388 rect,
389 content_offset,
390 node_data,
391 children,
392 }
393 }
394}
395
396#[derive(Debug, Clone)]
398pub struct LayoutNodeData {
399 pub modifier: Modifier,
400 pub resolved_modifiers: ResolvedModifiers,
401 pub modifier_slices: Rc<ModifierNodeSlices>,
402 pub kind: LayoutNodeKind,
403}
404
405impl LayoutNodeData {
406 pub fn new(
407 modifier: Modifier,
408 resolved_modifiers: ResolvedModifiers,
409 modifier_slices: Rc<ModifierNodeSlices>,
410 kind: LayoutNodeKind,
411 ) -> Self {
412 Self {
413 modifier,
414 resolved_modifiers,
415 modifier_slices,
416 kind,
417 }
418 }
419
420 pub fn resolved_modifiers(&self) -> ResolvedModifiers {
421 self.resolved_modifiers
422 }
423
424 pub fn modifier_slices(&self) -> &ModifierNodeSlices {
425 &self.modifier_slices
426 }
427}
428
429#[derive(Clone)]
436pub enum LayoutNodeKind {
437 Layout,
438 Subcompose,
439 Spacer,
440 Button { on_click: Rc<RefCell<dyn FnMut()>> },
441 Unknown,
442}
443
444impl fmt::Debug for LayoutNodeKind {
445 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
446 match self {
447 LayoutNodeKind::Layout => f.write_str("Layout"),
448 LayoutNodeKind::Subcompose => f.write_str("Subcompose"),
449 LayoutNodeKind::Spacer => f.write_str("Spacer"),
450 LayoutNodeKind::Button { .. } => f.write_str("Button"),
451 LayoutNodeKind::Unknown => f.write_str("Unknown"),
452 }
453 }
454}
455
456pub trait LayoutEngine {
458 fn compute_layout(&mut self, root: NodeId, max_size: Size) -> Result<LayoutTree, NodeError>;
459}
460
461impl LayoutEngine for MemoryApplier {
462 fn compute_layout(&mut self, root: NodeId, max_size: Size) -> Result<LayoutTree, NodeError> {
463 let measurements = measure_layout(self, root, max_size)?;
464 Ok(measurements.into_layout_tree())
465 }
466}
467
468#[derive(Debug, Clone)]
470pub struct LayoutMeasurements {
471 root: Rc<MeasuredNode>,
472 semantics: Option<SemanticsTree>,
473 layout_tree: LayoutTree,
474}
475
476impl LayoutMeasurements {
477 fn new(
478 root: Rc<MeasuredNode>,
479 semantics: Option<SemanticsTree>,
480 layout_tree: LayoutTree,
481 ) -> Self {
482 Self {
483 root,
484 semantics,
485 layout_tree,
486 }
487 }
488
489 pub fn root_size(&self) -> Size {
491 self.root.size
492 }
493
494 pub fn semantics_tree(&self) -> Option<&SemanticsTree> {
495 self.semantics.as_ref()
496 }
497
498 pub fn into_layout_tree(self) -> LayoutTree {
500 self.layout_tree
501 }
502
503 pub fn layout_tree(&self) -> LayoutTree {
505 self.layout_tree.clone()
506 }
507}
508
509#[derive(Clone, Copy, Debug, PartialEq, Eq)]
510pub struct MeasureLayoutOptions {
511 pub collect_semantics: bool,
512}
513
514impl Default for MeasureLayoutOptions {
515 fn default() -> Self {
516 Self {
517 collect_semantics: true,
518 }
519 }
520}
521
522pub fn tree_needs_layout(applier: &mut dyn Applier, root: NodeId) -> Result<bool, NodeError> {
530 let node = applier.get_mut(root)?;
532 let layout_node =
533 node.as_any_mut()
534 .downcast_mut::<LayoutNode>()
535 .ok_or(NodeError::TypeMismatch {
536 id: root,
537 expected: std::any::type_name::<LayoutNode>(),
538 })?;
539 Ok(layout_node.needs_layout())
540}
541
542#[cfg(test)]
544pub(crate) fn bubble_layout_dirty(applier: &mut MemoryApplier, node_id: NodeId) {
545 cranpose_core::bubble_layout_dirty(applier as &mut dyn Applier, node_id);
546}
547
548pub fn measure_layout(
550 applier: &mut MemoryApplier,
551 root: NodeId,
552 max_size: Size,
553) -> Result<LayoutMeasurements, NodeError> {
554 measure_layout_with_options(applier, root, max_size, MeasureLayoutOptions::default())
555}
556
557pub fn measure_layout_with_options(
558 applier: &mut MemoryApplier,
559 root: NodeId,
560 max_size: Size,
561 options: MeasureLayoutOptions,
562) -> Result<LayoutMeasurements, NodeError> {
563 let constraints = Constraints {
564 min_width: 0.0,
565 max_width: max_size.width,
566 min_height: 0.0,
567 max_height: max_size.height,
568 };
569
570 let (needs_remeasure, _needs_semantics, cached_epoch) = match applier
581 .with_node::<LayoutNode, _>(root, |node| {
582 (
583 node.needs_measure(), node.needs_semantics(),
585 node.cache_handles().epoch(),
586 )
587 }) {
588 Ok(tuple) => tuple,
589 Err(NodeError::TypeMismatch { .. }) => {
590 let node = applier.get_mut(root)?;
591 let measure_dirty = node.needs_layout();
593 let semantics_dirty = node.needs_semantics();
594 (measure_dirty, semantics_dirty, 0)
595 }
596 Err(err) => return Err(err),
597 };
598
599 let epoch = if needs_remeasure {
600 NEXT_CACHE_EPOCH.fetch_add(1, Ordering::Relaxed)
601 } else if cached_epoch != 0 {
602 cached_epoch
603 } else {
604 NEXT_CACHE_EPOCH.load(Ordering::Relaxed)
606 };
607
608 let guard = ApplierSlotGuard::new(applier);
616 let applier_host = guard.host();
617 let slots_handle = guard.slots_handle();
618
619 let mut builder =
622 LayoutBuilder::new_with_epoch(Rc::clone(&applier_host), epoch, Rc::clone(&slots_handle));
623
624 let measured = builder.measure_node(root, normalize_constraints(constraints))?;
629
630 if let Ok(mut applier) = applier_host.try_borrow_typed() {
634 if applier
635 .with_node::<LayoutNode, _>(root, |node| {
636 node.set_position(Point::default());
637 })
638 .is_err()
639 {
640 let _ = applier.with_node::<SubcomposeLayoutNode, _>(root, |node| {
641 node.set_position(Point::default());
642 });
643 }
644 }
645
646 let metadata = {
648 let mut applier_ref = applier_host.borrow_typed();
649 collect_runtime_metadata(&mut applier_ref, &measured)?
650 };
651
652 let semantics = if options.collect_semantics {
653 let semantics_snapshot = {
654 let mut applier_ref = applier_host.borrow_typed();
655 collect_semantics_snapshot(&mut applier_ref, &measured)?
656 };
657
658 Some(SemanticsTree::new(build_semantics_node(
659 &measured,
660 &metadata,
661 &semantics_snapshot,
662 )))
663 } else {
664 None
665 };
666
667 drop(builder);
670
671 let layout_tree = build_layout_tree_from_metadata(&measured, &metadata);
675
676 Ok(LayoutMeasurements::new(measured, semantics, layout_tree))
677}
678
679struct LayoutBuilder {
680 state: Rc<RefCell<LayoutBuilderState>>,
681}
682
683impl LayoutBuilder {
684 fn new_with_epoch(
685 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
686 epoch: u64,
687 slots: Rc<RefCell<SlotBackend>>,
688 ) -> Self {
689 Self {
690 state: Rc::new(RefCell::new(LayoutBuilderState::new_with_epoch(
691 applier, epoch, slots,
692 ))),
693 }
694 }
695
696 fn measure_node(
697 &mut self,
698 node_id: NodeId,
699 constraints: Constraints,
700 ) -> Result<Rc<MeasuredNode>, NodeError> {
701 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
702 }
703
704 fn set_runtime_handle(&mut self, handle: Option<RuntimeHandle>) {
705 self.state.borrow_mut().runtime_handle = handle;
706 }
707}
708
709struct LayoutBuilderState {
710 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
711 runtime_handle: Option<RuntimeHandle>,
712 slots: Rc<RefCell<SlotBackend>>,
715 cache_epoch: u64,
716 tmp_measurables: ScratchVecPool<Box<dyn Measurable>>,
717 tmp_records: ScratchVecPool<(NodeId, ChildRecord)>,
718 tmp_child_ids: ScratchVecPool<NodeId>,
719 tmp_layout_node_data: ScratchVecPool<LayoutModifierNodeData>,
720}
721
722impl LayoutBuilderState {
723 fn new_with_epoch(
724 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
725 epoch: u64,
726 slots: Rc<RefCell<SlotBackend>>,
727 ) -> Self {
728 let runtime_handle = applier.borrow_typed().runtime_handle();
729
730 Self {
731 applier,
732 runtime_handle,
733 slots,
734 cache_epoch: epoch,
735 tmp_measurables: ScratchVecPool::default(),
736 tmp_records: ScratchVecPool::default(),
737 tmp_child_ids: ScratchVecPool::default(),
738 tmp_layout_node_data: ScratchVecPool::default(),
739 }
740 }
741
742 fn try_with_applier_result<R>(
743 state_rc: &Rc<RefCell<Self>>,
744 f: impl FnOnce(&mut MemoryApplier) -> Result<R, NodeError>,
745 ) -> Option<Result<R, NodeError>> {
746 let host = {
747 let state = state_rc.borrow();
748 Rc::clone(&state.applier)
749 };
750
751 let Ok(mut applier) = host.try_borrow_typed() else {
753 return None;
754 };
755
756 Some(f(&mut applier))
757 }
758
759 fn with_applier_result<R>(
760 state_rc: &Rc<RefCell<Self>>,
761 f: impl FnOnce(&mut MemoryApplier) -> Result<R, NodeError>,
762 ) -> Result<R, NodeError> {
763 Self::try_with_applier_result(state_rc, f).unwrap_or_else(|| {
764 Err(NodeError::MissingContext {
765 id: NodeId::default(),
766 reason: "applier already borrowed",
767 })
768 })
769 }
770
771 fn clear_node_placed(state_rc: &Rc<RefCell<Self>>, node_id: NodeId) {
774 let host = {
775 let state = state_rc.borrow();
776 Rc::clone(&state.applier)
777 };
778 let Ok(mut applier) = host.try_borrow_typed() else {
779 return;
780 };
781 if applier
783 .with_node::<LayoutNode, _>(node_id, |node| {
784 node.clear_placed();
785 })
786 .is_err()
787 {
788 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
789 node.clear_placed();
790 });
791 }
792 }
793
794 fn measure_node(
795 state_rc: Rc<RefCell<Self>>,
796 node_id: NodeId,
797 constraints: Constraints,
798 ) -> Result<Rc<MeasuredNode>, NodeError> {
799 Self::clear_node_placed(&state_rc, node_id);
803
804 if let Some(subcompose) =
806 Self::try_measure_subcompose(Rc::clone(&state_rc), node_id, constraints)?
807 {
808 return Ok(subcompose);
809 }
810
811 if let Some(result) = Self::try_with_applier_result(&state_rc, |applier| {
813 match applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
814 LayoutNodeSnapshot::from_layout_node(layout_node)
815 }) {
816 Ok(snapshot) => Ok(Some(snapshot)),
817 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => Ok(None),
818 Err(err) => Err(err),
819 }
820 }) {
821 if let Some(snapshot) = result? {
823 return Self::measure_layout_node(
824 Rc::clone(&state_rc),
825 node_id,
826 snapshot,
827 constraints,
828 );
829 }
830 }
831 Ok(Rc::new(MeasuredNode::new(
836 node_id,
837 Size::default(),
838 Point { x: 0.0, y: 0.0 },
839 Point::default(), Vec::new(),
841 )))
842 }
843
844 fn try_measure_subcompose(
845 state_rc: Rc<RefCell<Self>>,
846 node_id: NodeId,
847 constraints: Constraints,
848 ) -> Result<Option<Rc<MeasuredNode>>, NodeError> {
849 let applier_host = {
850 let state = state_rc.borrow();
851 Rc::clone(&state.applier)
852 };
853
854 let (node_handle, resolved_modifiers) = {
855 let Ok(mut applier) = applier_host.try_borrow_typed() else {
857 return Ok(None);
858 };
859 let node = match applier.get_mut(node_id) {
860 Ok(node) => node,
861 Err(NodeError::Missing { .. }) => return Ok(None),
862 Err(err) => return Err(err),
863 };
864 let any = node.as_any_mut();
865 if let Some(subcompose) =
866 any.downcast_mut::<crate::subcompose_layout::SubcomposeLayoutNode>()
867 {
868 let handle = subcompose.handle();
869 let resolved_modifiers = handle.resolved_modifiers();
870 (handle, resolved_modifiers)
871 } else {
872 return Ok(None);
873 }
874 };
875
876 let runtime_handle = {
877 let mut state = state_rc.borrow_mut();
878 if state.runtime_handle.is_none() {
879 if let Ok(applier) = applier_host.try_borrow_typed() {
881 state.runtime_handle = applier.runtime_handle();
882 }
883 }
884 state
885 .runtime_handle
886 .clone()
887 .ok_or(NodeError::MissingContext {
888 id: node_id,
889 reason: "runtime handle required for subcomposition",
890 })?
891 };
892
893 let props = resolved_modifiers.layout_properties();
894 let padding = resolved_modifiers.padding();
895 let offset = resolved_modifiers.offset();
896 let mut inner_constraints = normalize_constraints(subtract_padding(constraints, padding));
897
898 if let DimensionConstraint::Points(width) = props.width() {
899 let constrained_width = width - padding.horizontal_sum();
900 inner_constraints.max_width = inner_constraints.max_width.min(constrained_width);
901 inner_constraints.min_width = inner_constraints.min_width.min(constrained_width);
902 }
903 if let DimensionConstraint::Points(height) = props.height() {
904 let constrained_height = height - padding.vertical_sum();
905 inner_constraints.max_height = inner_constraints.max_height.min(constrained_height);
906 inner_constraints.min_height = inner_constraints.min_height.min(constrained_height);
907 }
908
909 let mut slots_guard = SlotsGuard::take(Rc::clone(&state_rc));
910 let slots_host = slots_guard.host();
911 let applier_host_dyn: Rc<dyn ApplierHost> = applier_host.clone();
912 let observer = SnapshotStateObserver::new(|callback| callback());
913 let composer = Composer::new(
914 Rc::clone(&slots_host),
915 applier_host_dyn,
916 runtime_handle.clone(),
917 observer,
918 Some(node_id),
919 );
920 composer.enter_phase(Phase::Measure);
921
922 let state_rc_clone = Rc::clone(&state_rc);
923 let measure_error: Rc<RefCell<Option<NodeError>>> = Rc::new(RefCell::new(None));
924 let error_for_measurer = Rc::clone(&measure_error);
925 let measurer = Box::new(
926 move |child_id: NodeId, child_constraints: Constraints| -> Size {
927 match Self::measure_node(Rc::clone(&state_rc_clone), child_id, child_constraints) {
928 Ok(measured) => measured.size,
929 Err(err) => {
930 let mut slot = error_for_measurer.borrow_mut();
931 if slot.is_none() {
932 *slot = Some(err);
933 }
934 Size::default()
935 }
936 }
937 },
938 );
939
940 let measure_result = node_handle.measure(
941 &composer,
942 node_id,
943 inner_constraints,
944 measurer,
945 Rc::clone(&measure_error),
946 )?;
947
948 slots_guard.restore(slots_host.take());
949
950 if let Some(err) = measure_error.borrow_mut().take() {
951 return Err(err);
952 }
953
954 let mut width = measure_result.size.width + padding.horizontal_sum();
958 let mut height = measure_result.size.height + padding.vertical_sum();
959
960 width = resolve_dimension(
961 width,
962 props.width(),
963 props.min_width(),
964 props.max_width(),
965 constraints.min_width,
966 constraints.max_width,
967 );
968 height = resolve_dimension(
969 height,
970 props.height(),
971 props.min_height(),
972 props.max_height(),
973 constraints.min_height,
974 constraints.max_height,
975 );
976
977 let mut children = Vec::with_capacity(measure_result.placements.len());
978
979 if let Ok(mut applier) = applier_host.try_borrow_typed() {
981 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |parent_node| {
982 parent_node.set_measured_size(Size { width, height });
983 });
984 }
985
986 for placement in measure_result.placements {
987 let child =
988 Self::measure_node(Rc::clone(&state_rc), placement.node_id, inner_constraints)?;
989 let position = Point {
990 x: padding.left + placement.x,
991 y: padding.top + placement.y,
992 };
993
994 if let Ok(mut applier) = applier_host.try_borrow_typed() {
998 let _ = applier.with_node::<LayoutNode, _>(placement.node_id, |node| {
999 node.set_position(position);
1000 });
1001 }
1002
1003 children.push(MeasuredChild {
1004 node: child,
1005 offset: position,
1006 });
1007 }
1008
1009 node_handle.set_active_children(children.iter().map(|c| c.node.node_id));
1011
1012 Ok(Some(Rc::new(MeasuredNode::new(
1013 node_id,
1014 Size { width, height },
1015 offset,
1016 Point::default(), children,
1018 ))))
1019 }
1020 fn measure_through_modifier_chain(
1027 state_rc: &Rc<RefCell<Self>>,
1028 node_id: NodeId,
1029 measurables: &[Box<dyn Measurable>],
1030 measure_policy: &Rc<dyn MeasurePolicy>,
1031 constraints: Constraints,
1032 layout_node_data: &mut Vec<LayoutModifierNodeData>,
1033 ) -> ModifierChainMeasurement {
1034 use cranpose_foundation::NodeCapabilities;
1035
1036 layout_node_data.clear();
1038 let mut offset = Point::default();
1039
1040 {
1041 let state = state_rc.borrow();
1042 let mut applier = state.applier.borrow_typed();
1043
1044 let _ = applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1045 let chain_handle = layout_node.modifier_chain();
1046
1047 if !chain_handle.has_layout_nodes() {
1048 return;
1049 }
1050
1051 chain_handle.chain().for_each_forward_matching(
1053 NodeCapabilities::LAYOUT,
1054 |node_ref| {
1055 if let Some(index) = node_ref.entry_index() {
1056 if let Some(node_rc) = chain_handle.chain().get_node_rc(index) {
1058 layout_node_data.push((index, Rc::clone(&node_rc)));
1059 }
1060
1061 node_ref.with_node(|node| {
1065 if let Some(offset_node) =
1066 node.as_any()
1067 .downcast_ref::<crate::modifier_nodes::OffsetNode>()
1068 {
1069 let delta = offset_node.offset();
1070 offset.x += delta.x;
1071 offset.y += delta.y;
1072 }
1073 });
1074 }
1075 },
1076 );
1077 });
1078 }
1079
1080 if layout_node_data.is_empty() {
1083 let result = measure_policy.measure(measurables, constraints);
1084 let final_size = result.size;
1085 let placements = result.placements;
1086
1087 return ModifierChainMeasurement {
1088 result: MeasureResult {
1089 size: final_size,
1090 placements,
1091 },
1092 content_offset: Point::default(),
1093 offset,
1094 };
1095 }
1096
1097 let shared_context = Rc::new(RefCell::new(LayoutNodeContext::new()));
1102
1103 let policy_result = Rc::new(RefCell::new(None));
1105 let inner_coordinator: Box<dyn NodeCoordinator + '_> =
1106 Box::new(coordinator::InnerCoordinator::new(
1107 Rc::clone(measure_policy),
1108 measurables,
1109 Rc::clone(&policy_result),
1110 ));
1111
1112 let mut current_coordinator = inner_coordinator;
1114 while let Some((_, node_rc)) = layout_node_data.pop() {
1115 current_coordinator = Box::new(coordinator::LayoutModifierCoordinator::new(
1116 node_rc,
1117 current_coordinator,
1118 Rc::clone(&shared_context),
1119 ));
1120 }
1121
1122 let placeable = current_coordinator.measure(constraints);
1124 let final_size = Size {
1125 width: placeable.width(),
1126 height: placeable.height(),
1127 };
1128
1129 let content_offset = placeable.content_offset();
1131 let all_placement_offset = Point {
1132 x: content_offset.0,
1133 y: content_offset.1,
1134 };
1135
1136 let content_offset = Point {
1140 x: all_placement_offset.x - offset.x,
1141 y: all_placement_offset.y - offset.y,
1142 };
1143
1144 let placements = policy_result
1147 .borrow_mut()
1148 .take()
1149 .map(|result| result.placements)
1150 .unwrap_or_default();
1151
1152 let invalidations = shared_context.borrow_mut().take_invalidations();
1154 if !invalidations.is_empty() {
1155 Self::with_applier_result(state_rc, |applier| {
1157 applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1158 for kind in invalidations {
1159 match kind {
1160 InvalidationKind::Layout => layout_node.mark_needs_measure(),
1161 InvalidationKind::Draw => layout_node.mark_needs_redraw(),
1162 InvalidationKind::Semantics => layout_node.mark_needs_semantics(),
1163 InvalidationKind::PointerInput => layout_node.mark_needs_pointer_pass(),
1164 InvalidationKind::Focus => layout_node.mark_needs_focus_sync(),
1165 }
1166 }
1167 })
1168 })
1169 .ok();
1170 }
1171
1172 ModifierChainMeasurement {
1173 result: MeasureResult {
1174 size: final_size,
1175 placements,
1176 },
1177 content_offset,
1178 offset,
1179 }
1180 }
1181
1182 fn measure_layout_node(
1183 state_rc: Rc<RefCell<Self>>,
1184 node_id: NodeId,
1185 snapshot: LayoutNodeSnapshot,
1186 constraints: Constraints,
1187 ) -> Result<Rc<MeasuredNode>, NodeError> {
1188 let cache_epoch = {
1189 let state = state_rc.borrow();
1190 state.cache_epoch
1191 };
1192 let LayoutNodeSnapshot {
1193 resolved_modifiers,
1194 measure_policy,
1195 cache,
1196 needs_measure,
1197 } = snapshot;
1198 cache.activate(cache_epoch);
1199 let layout_props = resolved_modifiers.layout_properties();
1200
1201 if needs_measure {
1202 }
1204
1205 if !needs_measure {
1209 if let Some(cached) = cache.get_measurement(constraints) {
1211 Self::with_applier_result(&state_rc, |applier| {
1213 applier.with_node::<LayoutNode, _>(node_id, |node| {
1214 node.clear_needs_measure();
1215 node.clear_needs_layout();
1216 })
1217 })
1218 .ok();
1219 return Ok(cached);
1220 }
1221 }
1222
1223 let (runtime_handle, applier_host) = {
1224 let state = state_rc.borrow();
1225 (state.runtime_handle.clone(), Rc::clone(&state.applier))
1226 };
1227
1228 let measure_handle = LayoutMeasureHandle::new(Rc::clone(&state_rc));
1229 let error = Rc::new(RefCell::new(None));
1230 let mut pools = VecPools::acquire(Rc::clone(&state_rc));
1231 let (measurables, records, child_ids, layout_node_data) = pools.parts();
1232
1233 applier_host
1234 .borrow_typed()
1235 .with_node::<LayoutNode, _>(node_id, |node| {
1236 child_ids.extend_from_slice(&node.children);
1237 })?;
1238
1239 for &child_id in child_ids.iter() {
1240 let measured = Rc::new(RefCell::new(None));
1241 let position = Rc::new(RefCell::new(None));
1242
1243 let data = {
1244 let mut applier = applier_host.borrow_typed();
1245 match applier.with_node::<LayoutNode, _>(child_id, |n| {
1246 (n.cache_handles(), n.layout_state_handle())
1247 }) {
1248 Ok((cache, state)) => Some((cache, Some(state))),
1249 Err(NodeError::TypeMismatch { .. }) => {
1250 Some((LayoutNodeCacheHandles::default(), None))
1251 }
1252 Err(NodeError::Missing { .. }) => None,
1253 Err(err) => return Err(err),
1254 }
1255 };
1256
1257 let Some((cache_handles, layout_state)) = data else {
1258 continue;
1259 };
1260
1261 cache_handles.activate(cache_epoch);
1262
1263 records.push((
1264 child_id,
1265 ChildRecord {
1266 measured: Rc::clone(&measured),
1267 last_position: Rc::clone(&position),
1268 },
1269 ));
1270 measurables.push(Box::new(LayoutChildMeasurable::new(
1271 Rc::clone(&applier_host),
1272 child_id,
1273 measured,
1274 position,
1275 Rc::clone(&error),
1276 runtime_handle.clone(),
1277 cache_handles,
1278 cache_epoch,
1279 Some(measure_handle.clone()),
1280 layout_state,
1281 )));
1282 }
1283
1284 let has_weight = layout_props
1289 .weight()
1290 .map(|weight| weight.weight > 0.0)
1291 .unwrap_or(false);
1292 let chain_constraints = if has_weight {
1293 constraints
1294 } else {
1295 Constraints {
1296 min_width: constraints.min_width,
1297 max_width: if matches!(layout_props.width(), DimensionConstraint::Unspecified) {
1298 f32::INFINITY
1299 } else {
1300 constraints.max_width
1301 },
1302 min_height: constraints.min_height,
1303 max_height: if matches!(layout_props.height(), DimensionConstraint::Unspecified) {
1304 f32::INFINITY
1305 } else {
1306 constraints.max_height
1307 },
1308 }
1309 };
1310
1311 let mut modifier_chain_result = Self::measure_through_modifier_chain(
1312 &state_rc,
1313 node_id,
1314 measurables.as_slice(),
1315 &measure_policy,
1316 chain_constraints,
1317 layout_node_data,
1318 );
1319
1320 if (chain_constraints.max_width != constraints.max_width
1321 || chain_constraints.max_height != constraints.max_height)
1322 && ((constraints.max_width.is_finite()
1323 && modifier_chain_result.result.size.width > constraints.max_width)
1324 || (constraints.max_height.is_finite()
1325 && modifier_chain_result.result.size.height > constraints.max_height))
1326 {
1327 modifier_chain_result = Self::measure_through_modifier_chain(
1328 &state_rc,
1329 node_id,
1330 measurables.as_slice(),
1331 &measure_policy,
1332 constraints,
1333 layout_node_data,
1334 );
1335 }
1336
1337 let (width, height, policy_result, content_offset, offset) = {
1339 let result = modifier_chain_result;
1340 if let Some(err) = error.borrow_mut().take() {
1343 return Err(err);
1344 }
1345
1346 (
1347 result.result.size.width,
1348 result.result.size.height,
1349 result.result,
1350 result.content_offset,
1351 result.offset,
1352 )
1353 };
1354
1355 let mut measured_children = Vec::with_capacity(records.len());
1356 for (child_id, record) in records.iter() {
1357 if let Some(measured) = record.measured.borrow_mut().take() {
1358 let base_position = policy_result
1359 .placements
1360 .iter()
1361 .find(|placement| placement.node_id == *child_id)
1362 .map(|placement| Point {
1363 x: placement.x,
1364 y: placement.y,
1365 })
1366 .or_else(|| record.last_position.borrow().as_ref().copied())
1367 .unwrap_or(Point { x: 0.0, y: 0.0 });
1368 let position = Point {
1370 x: content_offset.x + base_position.x,
1371 y: content_offset.y + base_position.y,
1372 };
1373 measured_children.push(MeasuredChild {
1374 node: measured,
1375 offset: position,
1376 });
1377 }
1378 }
1379
1380 let measured = Rc::new(MeasuredNode::new(
1381 node_id,
1382 Size { width, height },
1383 offset,
1384 content_offset,
1385 measured_children,
1386 ));
1387
1388 cache.store_measurement(constraints, Rc::clone(&measured));
1389
1390 Self::with_applier_result(&state_rc, |applier| {
1392 applier.with_node::<LayoutNode, _>(node_id, |node| {
1393 node.clear_needs_measure();
1394 node.clear_needs_layout();
1395 node.set_measured_size(Size { width, height });
1396 node.set_content_offset(content_offset);
1397 })
1398 })
1399 .ok();
1400
1401 Ok(measured)
1402 }
1403}
1404
1405struct LayoutNodeSnapshot {
1412 resolved_modifiers: ResolvedModifiers,
1413 measure_policy: Rc<dyn MeasurePolicy>,
1414 cache: LayoutNodeCacheHandles,
1415 needs_measure: bool,
1417}
1418
1419impl LayoutNodeSnapshot {
1420 fn from_layout_node(node: &LayoutNode) -> Self {
1421 Self {
1422 resolved_modifiers: node.resolved_modifiers(),
1423 measure_policy: Rc::clone(&node.measure_policy),
1424 cache: node.cache_handles(),
1425 needs_measure: node.needs_measure(),
1426 }
1427 }
1428}
1429
1430struct VecPools {
1432 state: Rc<RefCell<LayoutBuilderState>>,
1433 measurables: Option<Vec<Box<dyn Measurable>>>,
1434 records: Option<Vec<(NodeId, ChildRecord)>>,
1435 child_ids: Option<Vec<NodeId>>,
1436 layout_node_data: Option<Vec<LayoutModifierNodeData>>,
1437}
1438
1439impl VecPools {
1440 fn acquire(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1441 let (measurables, records, child_ids, layout_node_data) = {
1442 let mut state_mut = state.borrow_mut();
1443 (
1444 state_mut.tmp_measurables.acquire(),
1445 state_mut.tmp_records.acquire(),
1446 state_mut.tmp_child_ids.acquire(),
1447 state_mut.tmp_layout_node_data.acquire(),
1448 )
1449 };
1450 Self {
1451 state,
1452 measurables: Some(measurables),
1453 records: Some(records),
1454 child_ids: Some(child_ids),
1455 layout_node_data: Some(layout_node_data),
1456 }
1457 }
1458
1459 #[allow(clippy::type_complexity)] fn parts(
1461 &mut self,
1462 ) -> (
1463 &mut Vec<Box<dyn Measurable>>,
1464 &mut Vec<(NodeId, ChildRecord)>,
1465 &mut Vec<NodeId>,
1466 &mut Vec<LayoutModifierNodeData>,
1467 ) {
1468 let measurables = self
1469 .measurables
1470 .as_mut()
1471 .expect("measurables already returned");
1472 let records = self.records.as_mut().expect("records already returned");
1473 let child_ids = self.child_ids.as_mut().expect("child_ids already returned");
1474 let layout_node_data = self
1475 .layout_node_data
1476 .as_mut()
1477 .expect("layout_node_data already returned");
1478 (measurables, records, child_ids, layout_node_data)
1479 }
1480}
1481
1482impl Drop for VecPools {
1483 fn drop(&mut self) {
1484 let mut state = self.state.borrow_mut();
1485 if let Some(measurables) = self.measurables.take() {
1486 state.tmp_measurables.release(measurables);
1487 }
1488 if let Some(records) = self.records.take() {
1489 state.tmp_records.release(records);
1490 }
1491 if let Some(child_ids) = self.child_ids.take() {
1492 state.tmp_child_ids.release(child_ids);
1493 }
1494 if let Some(layout_node_data) = self.layout_node_data.take() {
1495 state.tmp_layout_node_data.release(layout_node_data);
1496 }
1497 }
1498}
1499
1500struct SlotsGuard {
1501 state: Rc<RefCell<LayoutBuilderState>>,
1502 slots: Option<SlotBackend>,
1503}
1504
1505impl SlotsGuard {
1506 fn take(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1507 let slots = {
1508 let state_ref = state.borrow();
1509 let mut slots_ref = state_ref.slots.borrow_mut();
1510 std::mem::take(&mut *slots_ref)
1511 };
1512 Self {
1513 state,
1514 slots: Some(slots),
1515 }
1516 }
1517
1518 fn host(&mut self) -> Rc<SlotsHost> {
1519 let slots = self.slots.take().unwrap_or_default();
1520 Rc::new(SlotsHost::new(slots))
1521 }
1522
1523 fn restore(&mut self, slots: SlotBackend) {
1524 debug_assert!(self.slots.is_none());
1525 self.slots = Some(slots);
1526 }
1527}
1528
1529impl Drop for SlotsGuard {
1530 fn drop(&mut self) {
1531 if let Some(slots) = self.slots.take() {
1532 let state_ref = self.state.borrow();
1533 *state_ref.slots.borrow_mut() = slots;
1534 }
1535 }
1536}
1537
1538#[derive(Clone)]
1539struct LayoutMeasureHandle {
1540 state: Rc<RefCell<LayoutBuilderState>>,
1541}
1542
1543impl LayoutMeasureHandle {
1544 fn new(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1545 Self { state }
1546 }
1547
1548 fn measure(
1549 &self,
1550 node_id: NodeId,
1551 constraints: Constraints,
1552 ) -> Result<Rc<MeasuredNode>, NodeError> {
1553 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
1554 }
1555}
1556
1557#[derive(Debug, Clone)]
1558pub(crate) struct MeasuredNode {
1559 node_id: NodeId,
1560 size: Size,
1561 offset: Point,
1563 content_offset: Point,
1565 children: Vec<MeasuredChild>,
1566}
1567
1568impl MeasuredNode {
1569 fn new(
1570 node_id: NodeId,
1571 size: Size,
1572 offset: Point,
1573 content_offset: Point,
1574 children: Vec<MeasuredChild>,
1575 ) -> Self {
1576 Self {
1577 node_id,
1578 size,
1579 offset,
1580 content_offset,
1581 children,
1582 }
1583 }
1584}
1585
1586#[derive(Debug, Clone)]
1587struct MeasuredChild {
1588 node: Rc<MeasuredNode>,
1589 offset: Point,
1590}
1591
1592struct ChildRecord {
1593 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1594 last_position: Rc<RefCell<Option<Point>>>,
1595}
1596
1597struct LayoutChildMeasurable {
1598 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1599 node_id: NodeId,
1600 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1601 last_position: Rc<RefCell<Option<Point>>>,
1602 error: Rc<RefCell<Option<NodeError>>>,
1603 runtime_handle: Option<RuntimeHandle>,
1604 cache: LayoutNodeCacheHandles,
1605 cache_epoch: u64,
1606 measure_handle: Option<LayoutMeasureHandle>,
1607 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1608}
1609
1610impl LayoutChildMeasurable {
1611 #[allow(clippy::too_many_arguments)] fn new(
1613 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1614 node_id: NodeId,
1615 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1616 last_position: Rc<RefCell<Option<Point>>>,
1617 error: Rc<RefCell<Option<NodeError>>>,
1618 runtime_handle: Option<RuntimeHandle>,
1619 cache: LayoutNodeCacheHandles,
1620 cache_epoch: u64,
1621 measure_handle: Option<LayoutMeasureHandle>,
1622 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1623 ) -> Self {
1624 cache.activate(cache_epoch);
1625 Self {
1626 applier,
1627 node_id,
1628 measured,
1629 last_position,
1630 error,
1631 runtime_handle,
1632 cache,
1633 cache_epoch,
1634 measure_handle,
1635 layout_state,
1636 }
1637 }
1638
1639 fn record_error(&self, err: NodeError) {
1640 let mut slot = self.error.borrow_mut();
1641 if slot.is_none() {
1642 *slot = Some(err);
1643 }
1644 }
1645
1646 fn perform_measure(&self, constraints: Constraints) -> Result<Rc<MeasuredNode>, NodeError> {
1647 if let Some(handle) = &self.measure_handle {
1648 handle.measure(self.node_id, constraints)
1649 } else {
1650 measure_node_with_host(
1651 Rc::clone(&self.applier),
1652 self.runtime_handle.clone(),
1653 self.node_id,
1654 constraints,
1655 self.cache_epoch,
1656 )
1657 }
1658 }
1659
1660 fn intrinsic_measure(&self, constraints: Constraints) -> Option<Rc<MeasuredNode>> {
1661 self.cache.activate(self.cache_epoch);
1662 if let Some(cached) = self.cache.get_measurement(constraints) {
1663 return Some(cached);
1664 }
1665
1666 match self.perform_measure(constraints) {
1667 Ok(measured) => {
1668 self.cache
1669 .store_measurement(constraints, Rc::clone(&measured));
1670 Some(measured)
1671 }
1672 Err(err) => {
1673 self.record_error(err);
1674 None
1675 }
1676 }
1677 }
1678}
1679
1680impl Measurable for LayoutChildMeasurable {
1681 fn measure(&self, constraints: Constraints) -> Placeable {
1682 self.cache.activate(self.cache_epoch);
1683 let measured_size;
1684 if let Some(cached) = self.cache.get_measurement(constraints) {
1685 measured_size = cached.size;
1686 *self.measured.borrow_mut() = Some(Rc::clone(&cached));
1687 } else {
1688 match self.perform_measure(constraints) {
1689 Ok(measured) => {
1690 measured_size = measured.size;
1691 self.cache
1692 .store_measurement(constraints, Rc::clone(&measured));
1693 *self.measured.borrow_mut() = Some(measured);
1694 }
1695 Err(err) => {
1696 self.record_error(err);
1697 self.measured.borrow_mut().take();
1698 measured_size = Size {
1699 width: 0.0,
1700 height: 0.0,
1701 };
1702 }
1703 }
1704 }
1705
1706 if let Some(state) = &self.layout_state {
1709 let mut state = state.borrow_mut();
1710 state.size = measured_size;
1711 state.measurement_constraints = constraints;
1712 } else if let Ok(mut applier) = self.applier.try_borrow_typed() {
1713 let _ = applier.with_node::<LayoutNode, _>(self.node_id, |node| {
1714 node.set_measured_size(measured_size);
1715 node.set_measurement_constraints(constraints);
1716 });
1717 }
1718
1719 let applier = Rc::clone(&self.applier);
1721 let node_id = self.node_id;
1722 let measured = Rc::clone(&self.measured);
1723 let last_position = Rc::clone(&self.last_position);
1724 let layout_state = self.layout_state.clone();
1725
1726 let place_fn = Rc::new(move |x: f32, y: f32| {
1727 let internal_offset = measured
1729 .borrow()
1730 .as_ref()
1731 .map(|m| m.offset)
1732 .unwrap_or_default();
1733
1734 let position = Point {
1735 x: x + internal_offset.x,
1736 y: y + internal_offset.y,
1737 };
1738 *last_position.borrow_mut() = Some(position);
1739
1740 if let Some(state) = &layout_state {
1742 let mut state = state.borrow_mut();
1743 state.position = position;
1744 state.is_placed = true;
1745 } else if let Ok(mut applier) = applier.try_borrow_typed() {
1746 if applier
1747 .with_node::<LayoutNode, _>(node_id, |node| {
1748 node.set_position(position);
1749 })
1750 .is_err()
1751 {
1752 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1753 node.set_position(position);
1754 });
1755 }
1756 }
1757 });
1758
1759 Placeable::with_place_fn(
1760 measured_size.width,
1761 measured_size.height,
1762 self.node_id,
1763 place_fn,
1764 )
1765 }
1766
1767 fn min_intrinsic_width(&self, height: f32) -> f32 {
1768 let kind = IntrinsicKind::MinWidth(height);
1769 self.cache.activate(self.cache_epoch);
1770 if let Some(value) = self.cache.get_intrinsic(&kind) {
1771 return value;
1772 }
1773 let constraints = Constraints {
1774 min_width: 0.0,
1775 max_width: f32::INFINITY,
1776 min_height: height,
1777 max_height: height,
1778 };
1779 if let Some(node) = self.intrinsic_measure(constraints) {
1780 let value = node.size.width;
1781 self.cache.store_intrinsic(kind, value);
1782 value
1783 } else {
1784 0.0
1785 }
1786 }
1787
1788 fn max_intrinsic_width(&self, height: f32) -> f32 {
1789 let kind = IntrinsicKind::MaxWidth(height);
1790 self.cache.activate(self.cache_epoch);
1791 if let Some(value) = self.cache.get_intrinsic(&kind) {
1792 return value;
1793 }
1794 let constraints = Constraints {
1795 min_width: 0.0,
1796 max_width: f32::INFINITY,
1797 min_height: 0.0,
1798 max_height: height,
1799 };
1800 if let Some(node) = self.intrinsic_measure(constraints) {
1801 let value = node.size.width;
1802 self.cache.store_intrinsic(kind, value);
1803 value
1804 } else {
1805 0.0
1806 }
1807 }
1808
1809 fn min_intrinsic_height(&self, width: f32) -> f32 {
1810 let kind = IntrinsicKind::MinHeight(width);
1811 self.cache.activate(self.cache_epoch);
1812 if let Some(value) = self.cache.get_intrinsic(&kind) {
1813 return value;
1814 }
1815 let constraints = Constraints {
1816 min_width: width,
1817 max_width: width,
1818 min_height: 0.0,
1819 max_height: f32::INFINITY,
1820 };
1821 if let Some(node) = self.intrinsic_measure(constraints) {
1822 let value = node.size.height;
1823 self.cache.store_intrinsic(kind, value);
1824 value
1825 } else {
1826 0.0
1827 }
1828 }
1829
1830 fn max_intrinsic_height(&self, width: f32) -> f32 {
1831 let kind = IntrinsicKind::MaxHeight(width);
1832 self.cache.activate(self.cache_epoch);
1833 if let Some(value) = self.cache.get_intrinsic(&kind) {
1834 return value;
1835 }
1836 let constraints = Constraints {
1837 min_width: 0.0,
1838 max_width: width,
1839 min_height: 0.0,
1840 max_height: f32::INFINITY,
1841 };
1842 if let Some(node) = self.intrinsic_measure(constraints) {
1843 let value = node.size.height;
1844 self.cache.store_intrinsic(kind, value);
1845 value
1846 } else {
1847 0.0
1848 }
1849 }
1850
1851 fn flex_parent_data(&self) -> Option<cranpose_ui_layout::FlexParentData> {
1852 let Ok(mut applier) = self.applier.try_borrow_typed() else {
1855 return None;
1856 };
1857
1858 applier
1859 .with_node::<LayoutNode, _>(self.node_id, |layout_node| {
1860 let props = layout_node.resolved_modifiers().layout_properties();
1861 props.weight().map(|weight_data| {
1862 cranpose_ui_layout::FlexParentData::new(weight_data.weight, weight_data.fill)
1863 })
1864 })
1865 .ok()
1866 .flatten()
1867 }
1868}
1869
1870fn measure_node_with_host(
1871 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1872 runtime_handle: Option<RuntimeHandle>,
1873 node_id: NodeId,
1874 constraints: Constraints,
1875 epoch: u64,
1876) -> Result<Rc<MeasuredNode>, NodeError> {
1877 let runtime_handle = match runtime_handle {
1878 Some(handle) => Some(handle),
1879 None => applier.borrow_typed().runtime_handle(),
1880 };
1881 let mut builder = LayoutBuilder::new_with_epoch(
1882 applier,
1883 epoch,
1884 Rc::new(RefCell::new(SlotBackend::default())),
1885 );
1886 builder.set_runtime_handle(runtime_handle);
1887 builder.measure_node(node_id, constraints)
1888}
1889
1890#[derive(Clone)]
1891struct RuntimeNodeMetadata {
1892 modifier: Modifier,
1893 resolved_modifiers: ResolvedModifiers,
1894 modifier_slices: Rc<ModifierNodeSlices>,
1895 role: SemanticsRole,
1896 button_handler: Option<Rc<RefCell<dyn FnMut()>>>,
1897}
1898
1899impl Default for RuntimeNodeMetadata {
1900 fn default() -> Self {
1901 Self {
1902 modifier: Modifier::empty(),
1903 resolved_modifiers: ResolvedModifiers::default(),
1904 modifier_slices: Rc::default(),
1905 role: SemanticsRole::Unknown,
1906 button_handler: None,
1907 }
1908 }
1909}
1910
1911fn collect_runtime_metadata(
1912 applier: &mut MemoryApplier,
1913 node: &MeasuredNode,
1914) -> Result<HashMap<NodeId, RuntimeNodeMetadata>, NodeError> {
1915 let mut map = HashMap::default();
1916 collect_runtime_metadata_inner(applier, node, &mut map)?;
1917 Ok(map)
1918}
1919
1920fn collect_semantics_with_owner(
1922 applier: &mut MemoryApplier,
1923 node: &MeasuredNode,
1924 owner: &SemanticsOwner,
1925) -> Result<(), NodeError> {
1926 owner.get_or_compute(node.node_id, applier);
1928
1929 for child in &node.children {
1931 collect_semantics_with_owner(applier, &child.node, owner)?;
1932 }
1933 Ok(())
1934}
1935
1936fn collect_semantics_snapshot(
1937 applier: &mut MemoryApplier,
1938 node: &MeasuredNode,
1939) -> Result<HashMap<NodeId, Option<SemanticsConfiguration>>, NodeError> {
1940 let owner = SemanticsOwner::new();
1941 collect_semantics_with_owner(applier, node, &owner)?;
1942
1943 let mut map = HashMap::default();
1945 extract_configurations_recursive(node, &owner, &mut map);
1946 Ok(map)
1947}
1948
1949fn extract_configurations_recursive(
1950 node: &MeasuredNode,
1951 owner: &SemanticsOwner,
1952 map: &mut HashMap<NodeId, Option<SemanticsConfiguration>>,
1953) {
1954 if let Some(config) = owner.configurations.borrow().get(&node.node_id) {
1955 map.insert(node.node_id, config.clone());
1956 }
1957 for child in &node.children {
1958 extract_configurations_recursive(&child.node, owner, map);
1959 }
1960}
1961
1962fn collect_runtime_metadata_inner(
1963 applier: &mut MemoryApplier,
1964 node: &MeasuredNode,
1965 map: &mut HashMap<NodeId, RuntimeNodeMetadata>,
1966) -> Result<(), NodeError> {
1967 if let Entry::Vacant(entry) = map.entry(node.node_id) {
1968 let meta = runtime_metadata_for(applier, node.node_id)?;
1969 entry.insert(meta);
1970 }
1971 for child in &node.children {
1972 collect_runtime_metadata_inner(applier, &child.node, map)?;
1973 }
1974 Ok(())
1975}
1976
1977fn role_from_modifier_slices(modifier_slices: &ModifierNodeSlices) -> SemanticsRole {
1978 modifier_slices
1979 .text_content()
1980 .map(|text| SemanticsRole::Text {
1981 value: text.to_string(),
1982 })
1983 .unwrap_or(SemanticsRole::Layout)
1984}
1985
1986fn runtime_metadata_for(
1987 applier: &mut MemoryApplier,
1988 node_id: NodeId,
1989) -> Result<RuntimeNodeMetadata, NodeError> {
1990 if let Ok(meta) = applier.with_node::<LayoutNode, _>(node_id, |layout| {
1995 let modifier = layout.modifier.clone();
1996 let resolved_modifiers = layout.resolved_modifiers();
1997 let modifier_slices = layout.modifier_slices_snapshot();
1998 let role = role_from_modifier_slices(&modifier_slices);
1999
2000 RuntimeNodeMetadata {
2001 modifier,
2002 resolved_modifiers,
2003 modifier_slices,
2004 role,
2005 button_handler: None,
2006 }
2007 }) {
2008 return Ok(meta);
2009 }
2010
2011 if let Ok((modifier, resolved_modifiers, modifier_slices)) = applier
2013 .with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
2014 (
2015 node.modifier(),
2016 node.resolved_modifiers(),
2017 node.modifier_slices_snapshot(),
2018 )
2019 })
2020 {
2021 return Ok(RuntimeNodeMetadata {
2022 modifier,
2023 resolved_modifiers,
2024 modifier_slices,
2025 role: SemanticsRole::Subcompose,
2026 button_handler: None,
2027 });
2028 }
2029 Ok(RuntimeNodeMetadata::default())
2030}
2031
2032fn compute_semantics_for_node(
2036 applier: &mut MemoryApplier,
2037 node_id: NodeId,
2038) -> Option<SemanticsConfiguration> {
2039 match applier.with_node::<LayoutNode, _>(node_id, |layout| {
2041 let config = layout.semantics_configuration();
2042 layout.clear_needs_semantics();
2043 config
2044 }) {
2045 Ok(config) => return config,
2046 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {}
2047 Err(_) => return None,
2048 }
2049
2050 if let Ok(modifier) =
2052 applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| node.modifier())
2053 {
2054 return collect_semantics_from_modifier(&modifier);
2055 }
2056
2057 None
2058}
2059
2060fn build_semantics_node(
2064 node: &MeasuredNode,
2065 metadata: &HashMap<NodeId, RuntimeNodeMetadata>,
2066 semantics: &HashMap<NodeId, Option<SemanticsConfiguration>>,
2067) -> SemanticsNode {
2068 let info = metadata.get(&node.node_id).cloned().unwrap_or_default();
2069
2070 let mut role = info.role.clone();
2072 let mut actions = Vec::new();
2073 let mut description = None;
2074
2075 if let Some(config) = semantics.get(&node.node_id).cloned().flatten() {
2077 if config.is_button {
2079 role = SemanticsRole::Button;
2080 }
2081
2082 if config.is_clickable {
2084 actions.push(SemanticsAction::Click {
2085 handler: SemanticsCallback::new(node.node_id),
2086 });
2087 }
2088
2089 if let Some(desc) = config.content_description {
2091 description = Some(desc);
2092 }
2093 }
2094
2095 let children = node
2096 .children
2097 .iter()
2098 .map(|child| build_semantics_node(&child.node, metadata, semantics))
2099 .collect();
2100
2101 SemanticsNode::new(node.node_id, role, actions, children, description)
2102}
2103
2104fn build_layout_tree_from_metadata(
2105 node: &MeasuredNode,
2106 metadata: &HashMap<NodeId, RuntimeNodeMetadata>,
2107) -> LayoutTree {
2108 fn place(
2109 node: &MeasuredNode,
2110 origin: Point,
2111 metadata: &HashMap<NodeId, RuntimeNodeMetadata>,
2112 ) -> LayoutBox {
2113 let top_left = Point {
2115 x: origin.x + node.offset.x,
2116 y: origin.y + node.offset.y,
2117 };
2118 let rect = GeometryRect {
2119 x: top_left.x,
2120 y: top_left.y,
2121 width: node.size.width,
2122 height: node.size.height,
2123 };
2124 let info = metadata.get(&node.node_id).cloned().unwrap_or_default();
2125 let kind = layout_kind_from_metadata(node.node_id, &info);
2126 let data = LayoutNodeData::new(
2127 info.modifier.clone(),
2128 info.resolved_modifiers,
2129 info.modifier_slices.clone(),
2130 kind,
2131 );
2132 let children = node
2133 .children
2134 .iter()
2135 .map(|child| {
2136 let child_origin = Point {
2137 x: top_left.x + child.offset.x,
2138 y: top_left.y + child.offset.y,
2139 };
2140 place(&child.node, child_origin, metadata)
2141 })
2142 .collect();
2143 LayoutBox::new(node.node_id, rect, node.content_offset, data, children)
2144 }
2145
2146 LayoutTree::new(place(node, Point { x: 0.0, y: 0.0 }, metadata))
2147}
2148
2149fn layout_kind_from_metadata(_node_id: NodeId, info: &RuntimeNodeMetadata) -> LayoutNodeKind {
2150 match &info.role {
2151 SemanticsRole::Layout => LayoutNodeKind::Layout,
2152 SemanticsRole::Subcompose => LayoutNodeKind::Subcompose,
2153 SemanticsRole::Text { .. } => {
2154 LayoutNodeKind::Layout
2158 }
2159 SemanticsRole::Spacer => LayoutNodeKind::Spacer,
2160 SemanticsRole::Button => {
2161 let handler = info
2162 .button_handler
2163 .as_ref()
2164 .cloned()
2165 .unwrap_or_else(|| Rc::new(RefCell::new(|| {})));
2166 LayoutNodeKind::Button { on_click: handler }
2167 }
2168 SemanticsRole::Unknown => LayoutNodeKind::Unknown,
2169 }
2170}
2171
2172fn subtract_padding(constraints: Constraints, padding: EdgeInsets) -> Constraints {
2173 let horizontal = padding.horizontal_sum();
2174 let vertical = padding.vertical_sum();
2175 let min_width = (constraints.min_width - horizontal).max(0.0);
2176 let mut max_width = constraints.max_width;
2177 if max_width.is_finite() {
2178 max_width = (max_width - horizontal).max(0.0);
2179 }
2180 let min_height = (constraints.min_height - vertical).max(0.0);
2181 let mut max_height = constraints.max_height;
2182 if max_height.is_finite() {
2183 max_height = (max_height - vertical).max(0.0);
2184 }
2185 normalize_constraints(Constraints {
2186 min_width,
2187 max_width,
2188 min_height,
2189 max_height,
2190 })
2191}
2192
2193#[cfg(test)]
2194pub(crate) fn align_horizontal(alignment: HorizontalAlignment, available: f32, child: f32) -> f32 {
2195 match alignment {
2196 HorizontalAlignment::Start => 0.0,
2197 HorizontalAlignment::CenterHorizontally => ((available - child) / 2.0).max(0.0),
2198 HorizontalAlignment::End => (available - child).max(0.0),
2199 }
2200}
2201
2202#[cfg(test)]
2203pub(crate) fn align_vertical(alignment: VerticalAlignment, available: f32, child: f32) -> f32 {
2204 match alignment {
2205 VerticalAlignment::Top => 0.0,
2206 VerticalAlignment::CenterVertically => ((available - child) / 2.0).max(0.0),
2207 VerticalAlignment::Bottom => (available - child).max(0.0),
2208 }
2209}
2210
2211fn resolve_dimension(
2212 base: f32,
2213 explicit: DimensionConstraint,
2214 min_override: Option<f32>,
2215 max_override: Option<f32>,
2216 min_limit: f32,
2217 max_limit: f32,
2218) -> f32 {
2219 let mut min_bound = min_limit;
2220 if let Some(min_value) = min_override {
2221 min_bound = min_bound.max(min_value);
2222 }
2223
2224 let mut max_bound = if max_limit.is_finite() {
2225 max_limit
2226 } else {
2227 max_override.unwrap_or(max_limit)
2228 };
2229 if let Some(max_value) = max_override {
2230 if max_bound.is_finite() {
2231 max_bound = max_bound.min(max_value);
2232 } else {
2233 max_bound = max_value;
2234 }
2235 }
2236 if max_bound < min_bound {
2237 max_bound = min_bound;
2238 }
2239
2240 let mut size = match explicit {
2241 DimensionConstraint::Points(points) => points,
2242 DimensionConstraint::Fraction(fraction) => {
2243 if max_limit.is_finite() {
2244 max_limit * fraction.clamp(0.0, 1.0)
2245 } else {
2246 base
2247 }
2248 }
2249 DimensionConstraint::Unspecified => base,
2250 DimensionConstraint::Intrinsic(_) => base,
2253 };
2254
2255 size = clamp_dimension(size, min_bound, max_bound);
2256 size = clamp_dimension(size, min_limit, max_limit);
2257 size.max(0.0)
2258}
2259
2260fn clamp_dimension(value: f32, min: f32, max: f32) -> f32 {
2261 let mut result = value.max(min);
2262 if max.is_finite() {
2263 result = result.min(max);
2264 }
2265 result
2266}
2267
2268fn normalize_constraints(mut constraints: Constraints) -> Constraints {
2269 if constraints.max_width < constraints.min_width {
2270 constraints.max_width = constraints.min_width;
2271 }
2272 if constraints.max_height < constraints.min_height {
2273 constraints.max_height = constraints.min_height;
2274 }
2275 constraints
2276}
2277
2278#[cfg(test)]
2279#[path = "tests/layout_tests.rs"]
2280mod tests;