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, collect_slices_from_modifier, DimensionConstraint, EdgeInsets,
28 Modifier, ModifierNodeSlices, 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
192#[derive(Clone, Debug, PartialEq, Eq)]
194pub struct SemanticsCallback {
195 node_id: NodeId,
196}
197
198impl SemanticsCallback {
199 pub fn new(node_id: NodeId) -> Self {
200 Self { node_id }
201 }
202
203 pub fn node_id(&self) -> NodeId {
204 self.node_id
205 }
206}
207
208#[derive(Clone, Debug, PartialEq, Eq)]
210pub enum SemanticsAction {
211 Click { handler: SemanticsCallback },
212}
213
214#[derive(Clone, Debug, PartialEq, Eq)]
217pub enum SemanticsRole {
218 Layout,
220 Subcompose,
222 Text { value: String },
224 Spacer,
226 Button,
228 Unknown,
230}
231
232#[derive(Clone, Debug)]
234pub struct SemanticsNode {
235 pub node_id: NodeId,
236 pub role: SemanticsRole,
237 pub actions: Vec<SemanticsAction>,
238 pub children: Vec<SemanticsNode>,
239 pub description: Option<String>,
240}
241
242impl SemanticsNode {
243 fn new(
244 node_id: NodeId,
245 role: SemanticsRole,
246 actions: Vec<SemanticsAction>,
247 children: Vec<SemanticsNode>,
248 description: Option<String>,
249 ) -> Self {
250 Self {
251 node_id,
252 role,
253 actions,
254 children,
255 description,
256 }
257 }
258}
259
260#[derive(Clone, Debug)]
262pub struct SemanticsTree {
263 root: SemanticsNode,
264}
265
266impl SemanticsTree {
267 fn new(root: SemanticsNode) -> Self {
268 Self { root }
269 }
270
271 pub fn root(&self) -> &SemanticsNode {
272 &self.root
273 }
274}
275
276#[derive(Default)]
279pub struct SemanticsOwner {
280 configurations: RefCell<HashMap<NodeId, Option<SemanticsConfiguration>>>,
281}
282
283impl SemanticsOwner {
284 pub fn new() -> Self {
285 Self {
286 configurations: RefCell::new(HashMap::default()),
287 }
288 }
289
290 pub fn get_or_compute(
292 &self,
293 node_id: NodeId,
294 applier: &mut MemoryApplier,
295 ) -> Option<SemanticsConfiguration> {
296 if let Some(cached) = self.configurations.borrow().get(&node_id) {
298 return cached.clone();
299 }
300
301 let config = compute_semantics_for_node(applier, node_id);
303 self.configurations
304 .borrow_mut()
305 .insert(node_id, config.clone());
306 config
307 }
308}
309
310#[derive(Debug, Clone)]
312pub struct LayoutTree {
313 root: LayoutBox,
314}
315
316impl LayoutTree {
317 pub fn new(root: LayoutBox) -> Self {
318 Self { root }
319 }
320
321 pub fn root(&self) -> &LayoutBox {
322 &self.root
323 }
324
325 pub fn root_mut(&mut self) -> &mut LayoutBox {
326 &mut self.root
327 }
328
329 pub fn into_root(self) -> LayoutBox {
330 self.root
331 }
332}
333
334#[derive(Debug, Clone)]
336pub struct LayoutBox {
337 pub node_id: NodeId,
338 pub rect: GeometryRect,
339 pub content_offset: Point,
341 pub node_data: LayoutNodeData,
342 pub children: Vec<LayoutBox>,
343}
344
345impl LayoutBox {
346 pub fn new(
347 node_id: NodeId,
348 rect: GeometryRect,
349 content_offset: Point,
350 node_data: LayoutNodeData,
351 children: Vec<LayoutBox>,
352 ) -> Self {
353 Self {
354 node_id,
355 rect,
356 content_offset,
357 node_data,
358 children,
359 }
360 }
361}
362
363#[derive(Debug, Clone)]
365pub struct LayoutNodeData {
366 pub modifier: Modifier,
367 pub resolved_modifiers: ResolvedModifiers,
368 pub modifier_slices: Rc<ModifierNodeSlices>,
369 pub kind: LayoutNodeKind,
370}
371
372impl LayoutNodeData {
373 pub fn new(
374 modifier: Modifier,
375 resolved_modifiers: ResolvedModifiers,
376 modifier_slices: Rc<ModifierNodeSlices>,
377 kind: LayoutNodeKind,
378 ) -> Self {
379 Self {
380 modifier,
381 resolved_modifiers,
382 modifier_slices,
383 kind,
384 }
385 }
386
387 pub fn resolved_modifiers(&self) -> ResolvedModifiers {
388 self.resolved_modifiers
389 }
390
391 pub fn modifier_slices(&self) -> &ModifierNodeSlices {
392 &self.modifier_slices
393 }
394}
395
396#[derive(Clone)]
403pub enum LayoutNodeKind {
404 Layout,
405 Subcompose,
406 Spacer,
407 Button { on_click: Rc<RefCell<dyn FnMut()>> },
408 Unknown,
409}
410
411impl fmt::Debug for LayoutNodeKind {
412 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
413 match self {
414 LayoutNodeKind::Layout => f.write_str("Layout"),
415 LayoutNodeKind::Subcompose => f.write_str("Subcompose"),
416 LayoutNodeKind::Spacer => f.write_str("Spacer"),
417 LayoutNodeKind::Button { .. } => f.write_str("Button"),
418 LayoutNodeKind::Unknown => f.write_str("Unknown"),
419 }
420 }
421}
422
423pub trait LayoutEngine {
425 fn compute_layout(&mut self, root: NodeId, max_size: Size) -> Result<LayoutTree, NodeError>;
426}
427
428impl LayoutEngine for MemoryApplier {
429 fn compute_layout(&mut self, root: NodeId, max_size: Size) -> Result<LayoutTree, NodeError> {
430 let measurements = measure_layout(self, root, max_size)?;
431 Ok(measurements.into_layout_tree())
432 }
433}
434
435#[derive(Debug, Clone)]
437pub struct LayoutMeasurements {
438 root: Rc<MeasuredNode>,
439 semantics: SemanticsTree,
440 layout_tree: LayoutTree,
441}
442
443impl LayoutMeasurements {
444 fn new(root: Rc<MeasuredNode>, semantics: SemanticsTree, layout_tree: LayoutTree) -> Self {
445 Self {
446 root,
447 semantics,
448 layout_tree,
449 }
450 }
451
452 pub fn root_size(&self) -> Size {
454 self.root.size
455 }
456
457 pub fn semantics_tree(&self) -> &SemanticsTree {
458 &self.semantics
459 }
460
461 pub fn into_layout_tree(self) -> LayoutTree {
463 self.layout_tree
464 }
465
466 pub fn layout_tree(&self) -> LayoutTree {
468 self.layout_tree.clone()
469 }
470}
471
472pub fn tree_needs_layout(applier: &mut dyn Applier, root: NodeId) -> Result<bool, NodeError> {
480 let node = applier.get_mut(root)?;
482 let layout_node =
483 node.as_any_mut()
484 .downcast_mut::<LayoutNode>()
485 .ok_or(NodeError::TypeMismatch {
486 id: root,
487 expected: std::any::type_name::<LayoutNode>(),
488 })?;
489 Ok(layout_node.needs_layout())
490}
491
492#[cfg(test)]
494pub(crate) fn bubble_layout_dirty(applier: &mut MemoryApplier, node_id: NodeId) {
495 cranpose_core::bubble_layout_dirty(applier as &mut dyn Applier, node_id);
496}
497
498pub fn measure_layout(
500 applier: &mut MemoryApplier,
501 root: NodeId,
502 max_size: Size,
503) -> Result<LayoutMeasurements, NodeError> {
504 let constraints = Constraints {
505 min_width: 0.0,
506 max_width: max_size.width,
507 min_height: 0.0,
508 max_height: max_size.height,
509 };
510
511 let (needs_remeasure, _needs_semantics, cached_epoch) = match applier
522 .with_node::<LayoutNode, _>(root, |node| {
523 (
524 node.needs_measure(), node.needs_semantics(),
526 node.cache_handles().epoch(),
527 )
528 }) {
529 Ok(tuple) => tuple,
530 Err(NodeError::TypeMismatch { .. }) => {
531 let node = applier.get_mut(root)?;
532 let measure_dirty = node.needs_layout();
534 let semantics_dirty = node.needs_semantics();
535 (measure_dirty, semantics_dirty, 0)
536 }
537 Err(err) => return Err(err),
538 };
539
540 let epoch = if needs_remeasure {
541 NEXT_CACHE_EPOCH.fetch_add(1, Ordering::Relaxed)
542 } else if cached_epoch != 0 {
543 cached_epoch
544 } else {
545 NEXT_CACHE_EPOCH.load(Ordering::Relaxed)
547 };
548
549 let guard = ApplierSlotGuard::new(applier);
557 let applier_host = guard.host();
558 let slots_handle = guard.slots_handle();
559
560 let mut builder =
563 LayoutBuilder::new_with_epoch(Rc::clone(&applier_host), epoch, Rc::clone(&slots_handle));
564
565 let measured = builder.measure_node(root, normalize_constraints(constraints))?;
570
571 if let Ok(mut applier) = applier_host.try_borrow_typed() {
575 if applier
576 .with_node::<LayoutNode, _>(root, |node| {
577 node.set_position(Point::default());
578 })
579 .is_err()
580 {
581 let _ = applier.with_node::<SubcomposeLayoutNode, _>(root, |node| {
582 node.set_position(Point::default());
583 });
584 }
585 }
586
587 let metadata = {
589 let mut applier_ref = applier_host.borrow_typed();
590 collect_runtime_metadata(&mut applier_ref, &measured)?
591 };
592
593 let semantics_snapshot = {
595 let mut applier_ref = applier_host.borrow_typed();
596 collect_semantics_snapshot(&mut applier_ref, &measured)?
597 };
598
599 drop(builder);
602
603 let semantics_root = build_semantics_node(&measured, &metadata, &semantics_snapshot);
608 let semantics = SemanticsTree::new(semantics_root);
609 let layout_tree = build_layout_tree_from_metadata(&measured, &metadata);
610
611 Ok(LayoutMeasurements::new(measured, semantics, layout_tree))
612}
613
614struct LayoutBuilder {
615 state: Rc<RefCell<LayoutBuilderState>>,
616}
617
618impl LayoutBuilder {
619 fn new_with_epoch(
620 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
621 epoch: u64,
622 slots: Rc<RefCell<SlotBackend>>,
623 ) -> Self {
624 Self {
625 state: Rc::new(RefCell::new(LayoutBuilderState::new_with_epoch(
626 applier, epoch, slots,
627 ))),
628 }
629 }
630
631 fn measure_node(
632 &mut self,
633 node_id: NodeId,
634 constraints: Constraints,
635 ) -> Result<Rc<MeasuredNode>, NodeError> {
636 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
637 }
638
639 fn set_runtime_handle(&mut self, handle: Option<RuntimeHandle>) {
640 self.state.borrow_mut().runtime_handle = handle;
641 }
642}
643
644struct LayoutBuilderState {
645 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
646 runtime_handle: Option<RuntimeHandle>,
647 slots: Rc<RefCell<SlotBackend>>,
650 cache_epoch: u64,
651 tmp_measurables: Vec<Box<dyn Measurable>>,
652 tmp_records: Vec<(NodeId, ChildRecord)>,
653}
654
655impl LayoutBuilderState {
656 fn new_with_epoch(
657 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
658 epoch: u64,
659 slots: Rc<RefCell<SlotBackend>>,
660 ) -> Self {
661 let runtime_handle = applier.borrow_typed().runtime_handle();
662
663 Self {
664 applier,
665 runtime_handle,
666 slots,
667 cache_epoch: epoch,
668 tmp_measurables: Vec::new(),
669 tmp_records: Vec::new(),
670 }
671 }
672
673 fn try_with_applier_result<R>(
674 state_rc: &Rc<RefCell<Self>>,
675 f: impl FnOnce(&mut MemoryApplier) -> Result<R, NodeError>,
676 ) -> Option<Result<R, NodeError>> {
677 let host = {
678 let state = state_rc.borrow();
679 Rc::clone(&state.applier)
680 };
681
682 let Ok(mut applier) = host.try_borrow_typed() else {
684 return None;
685 };
686
687 Some(f(&mut applier))
688 }
689
690 fn with_applier_result<R>(
691 state_rc: &Rc<RefCell<Self>>,
692 f: impl FnOnce(&mut MemoryApplier) -> Result<R, NodeError>,
693 ) -> Result<R, NodeError> {
694 Self::try_with_applier_result(state_rc, f).unwrap_or_else(|| {
695 Err(NodeError::MissingContext {
696 id: NodeId::default(),
697 reason: "applier already borrowed",
698 })
699 })
700 }
701
702 fn clear_node_placed(state_rc: &Rc<RefCell<Self>>, node_id: NodeId) {
705 let host = {
706 let state = state_rc.borrow();
707 Rc::clone(&state.applier)
708 };
709 let Ok(mut applier) = host.try_borrow_typed() else {
710 return;
711 };
712 if applier
714 .with_node::<LayoutNode, _>(node_id, |node| {
715 node.clear_placed();
716 })
717 .is_err()
718 {
719 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
720 node.clear_placed();
721 });
722 }
723 }
724
725 fn measure_node(
726 state_rc: Rc<RefCell<Self>>,
727 node_id: NodeId,
728 constraints: Constraints,
729 ) -> Result<Rc<MeasuredNode>, NodeError> {
730 Self::clear_node_placed(&state_rc, node_id);
734
735 if let Some(subcompose) =
737 Self::try_measure_subcompose(Rc::clone(&state_rc), node_id, constraints)?
738 {
739 return Ok(subcompose);
740 }
741
742 if let Some(result) = Self::try_with_applier_result(&state_rc, |applier| {
744 match applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
745 LayoutNodeSnapshot::from_layout_node(layout_node)
746 }) {
747 Ok(snapshot) => Ok(Some(snapshot)),
748 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => Ok(None),
749 Err(err) => Err(err),
750 }
751 }) {
752 if let Some(snapshot) = result? {
754 return Self::measure_layout_node(
755 Rc::clone(&state_rc),
756 node_id,
757 snapshot,
758 constraints,
759 );
760 }
761 }
762 Ok(Rc::new(MeasuredNode::new(
767 node_id,
768 Size::default(),
769 Point { x: 0.0, y: 0.0 },
770 Point::default(), Vec::new(),
772 )))
773 }
774
775 fn try_measure_subcompose(
776 state_rc: Rc<RefCell<Self>>,
777 node_id: NodeId,
778 constraints: Constraints,
779 ) -> Result<Option<Rc<MeasuredNode>>, NodeError> {
780 let applier_host = {
781 let state = state_rc.borrow();
782 Rc::clone(&state.applier)
783 };
784
785 let (node_handle, resolved_modifiers) = {
786 let Ok(mut applier) = applier_host.try_borrow_typed() else {
788 return Ok(None);
789 };
790 let node = match applier.get_mut(node_id) {
791 Ok(node) => node,
792 Err(NodeError::Missing { .. }) => return Ok(None),
793 Err(err) => return Err(err),
794 };
795 let any = node.as_any_mut();
796 if let Some(subcompose) =
797 any.downcast_mut::<crate::subcompose_layout::SubcomposeLayoutNode>()
798 {
799 let handle = subcompose.handle();
800 let resolved_modifiers = handle.resolved_modifiers();
801 (handle, resolved_modifiers)
802 } else {
803 return Ok(None);
804 }
805 };
806
807 let runtime_handle = {
808 let mut state = state_rc.borrow_mut();
809 if state.runtime_handle.is_none() {
810 if let Ok(applier) = applier_host.try_borrow_typed() {
812 state.runtime_handle = applier.runtime_handle();
813 }
814 }
815 state
816 .runtime_handle
817 .clone()
818 .ok_or(NodeError::MissingContext {
819 id: node_id,
820 reason: "runtime handle required for subcomposition",
821 })?
822 };
823
824 let props = resolved_modifiers.layout_properties();
825 let padding = resolved_modifiers.padding();
826 let offset = resolved_modifiers.offset();
827 let mut inner_constraints = normalize_constraints(subtract_padding(constraints, padding));
828
829 if let DimensionConstraint::Points(width) = props.width() {
830 let constrained_width = width - padding.horizontal_sum();
831 inner_constraints.max_width = inner_constraints.max_width.min(constrained_width);
832 inner_constraints.min_width = inner_constraints.min_width.min(constrained_width);
833 }
834 if let DimensionConstraint::Points(height) = props.height() {
835 let constrained_height = height - padding.vertical_sum();
836 inner_constraints.max_height = inner_constraints.max_height.min(constrained_height);
837 inner_constraints.min_height = inner_constraints.min_height.min(constrained_height);
838 }
839
840 let mut slots_guard = SlotsGuard::take(Rc::clone(&state_rc));
841 let slots_host = slots_guard.host();
842 let applier_host_dyn: Rc<dyn ApplierHost> = applier_host.clone();
843 let observer = SnapshotStateObserver::new(|callback| callback());
844 let composer = Composer::new(
845 Rc::clone(&slots_host),
846 applier_host_dyn,
847 runtime_handle.clone(),
848 observer,
849 Some(node_id),
850 );
851 composer.enter_phase(Phase::Measure);
852
853 let state_rc_clone = Rc::clone(&state_rc);
854 let measure_error: Rc<RefCell<Option<NodeError>>> = Rc::new(RefCell::new(None));
855 let error_for_measurer = Rc::clone(&measure_error);
856 let measurer = Box::new(
857 move |child_id: NodeId, child_constraints: Constraints| -> Size {
858 match Self::measure_node(Rc::clone(&state_rc_clone), child_id, child_constraints) {
859 Ok(measured) => measured.size,
860 Err(err) => {
861 let mut slot = error_for_measurer.borrow_mut();
862 if slot.is_none() {
863 *slot = Some(err);
864 }
865 Size::default()
866 }
867 }
868 },
869 );
870
871 let measure_result = node_handle.measure(
872 &composer,
873 node_id,
874 inner_constraints,
875 measurer,
876 Rc::clone(&measure_error),
877 )?;
878
879 slots_guard.restore(slots_host.take());
880
881 if let Some(err) = measure_error.borrow_mut().take() {
882 return Err(err);
883 }
884
885 let mut width = measure_result.size.width + padding.horizontal_sum();
889 let mut height = measure_result.size.height + padding.vertical_sum();
890
891 width = resolve_dimension(
892 width,
893 props.width(),
894 props.min_width(),
895 props.max_width(),
896 constraints.min_width,
897 constraints.max_width,
898 );
899 height = resolve_dimension(
900 height,
901 props.height(),
902 props.min_height(),
903 props.max_height(),
904 constraints.min_height,
905 constraints.max_height,
906 );
907
908 let mut children = Vec::new();
909
910 if let Ok(mut applier) = applier_host.try_borrow_typed() {
912 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |parent_node| {
913 parent_node.set_measured_size(Size { width, height });
914 });
915 }
916
917 for placement in measure_result.placements {
918 let child =
919 Self::measure_node(Rc::clone(&state_rc), placement.node_id, inner_constraints)?;
920 let position = Point {
921 x: padding.left + placement.x,
922 y: padding.top + placement.y,
923 };
924
925 if let Ok(mut applier) = applier_host.try_borrow_typed() {
929 let _ = applier.with_node::<LayoutNode, _>(placement.node_id, |node| {
930 node.set_position(position);
931 });
932 }
933
934 children.push(MeasuredChild {
935 node: child,
936 offset: position,
937 });
938 }
939
940 node_handle.set_active_children(children.iter().map(|c| c.node.node_id));
942
943 Ok(Some(Rc::new(MeasuredNode::new(
944 node_id,
945 Size { width, height },
946 offset,
947 Point::default(), children,
949 ))))
950 }
951 fn measure_through_modifier_chain(
958 state_rc: &Rc<RefCell<Self>>,
959 node_id: NodeId,
960 measurables: &[Box<dyn Measurable>],
961 measure_policy: &Rc<dyn MeasurePolicy>,
962 constraints: Constraints,
963 ) -> ModifierChainMeasurement {
964 use cranpose_foundation::NodeCapabilities;
965
966 #[allow(clippy::type_complexity)]
968 let mut layout_node_data: Vec<(
970 usize,
971 Rc<RefCell<Box<dyn cranpose_foundation::ModifierNode>>>,
972 )> = Vec::new();
973 let mut offset = Point::default();
974
975 {
976 let state = state_rc.borrow();
977 let mut applier = state.applier.borrow_typed();
978
979 let _ = applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
980 let chain_handle = layout_node.modifier_chain();
981
982 if !chain_handle.has_layout_nodes() {
983 return;
984 }
985
986 chain_handle.chain().for_each_forward_matching(
988 NodeCapabilities::LAYOUT,
989 |node_ref| {
990 if let Some(index) = node_ref.entry_index() {
991 if let Some(node_rc) = chain_handle.chain().get_node_rc(index) {
993 layout_node_data.push((index, Rc::clone(&node_rc)));
994 }
995
996 node_ref.with_node(|node| {
1000 if let Some(offset_node) =
1001 node.as_any()
1002 .downcast_ref::<crate::modifier_nodes::OffsetNode>()
1003 {
1004 let delta = offset_node.offset();
1005 offset.x += delta.x;
1006 offset.y += delta.y;
1007 }
1008 });
1009 }
1010 },
1011 );
1012 });
1013 }
1014
1015 layout_node_data.reverse();
1022
1023 let shared_context = Rc::new(RefCell::new(LayoutNodeContext::new()));
1025
1026 let policy_result = Rc::new(RefCell::new(None));
1028 let inner_coordinator: Box<dyn NodeCoordinator + '_> =
1029 Box::new(coordinator::InnerCoordinator::new(
1030 Rc::clone(measure_policy),
1031 measurables,
1032 Rc::clone(&policy_result),
1033 ));
1034
1035 let mut current_coordinator = inner_coordinator;
1037 for (_, node_rc) in layout_node_data {
1038 current_coordinator = Box::new(coordinator::LayoutModifierCoordinator::new(
1039 node_rc,
1040 current_coordinator,
1041 Rc::clone(&shared_context),
1042 ));
1043 }
1044
1045 let placeable = current_coordinator.measure(constraints);
1047 let final_size = Size {
1048 width: placeable.width(),
1049 height: placeable.height(),
1050 };
1051
1052 let content_offset = placeable.content_offset();
1054 let all_placement_offset = Point {
1055 x: content_offset.0,
1056 y: content_offset.1,
1057 };
1058
1059 let content_offset = Point {
1063 x: all_placement_offset.x - offset.x,
1064 y: all_placement_offset.y - offset.y,
1065 };
1066
1067 let placements = policy_result
1070 .borrow_mut()
1071 .take()
1072 .map(|result| result.placements)
1073 .unwrap_or_default();
1074
1075 let invalidations = shared_context.borrow_mut().take_invalidations();
1077 if !invalidations.is_empty() {
1078 Self::with_applier_result(state_rc, |applier| {
1080 applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1081 for kind in invalidations {
1082 match kind {
1083 InvalidationKind::Layout => layout_node.mark_needs_measure(),
1084 InvalidationKind::Draw => layout_node.mark_needs_redraw(),
1085 InvalidationKind::Semantics => layout_node.mark_needs_semantics(),
1086 InvalidationKind::PointerInput => layout_node.mark_needs_pointer_pass(),
1087 InvalidationKind::Focus => layout_node.mark_needs_focus_sync(),
1088 }
1089 }
1090 })
1091 })
1092 .ok();
1093 }
1094
1095 ModifierChainMeasurement {
1096 result: MeasureResult {
1097 size: final_size,
1098 placements,
1099 },
1100 content_offset,
1101 offset,
1102 }
1103 }
1104
1105 fn measure_layout_node(
1106 state_rc: Rc<RefCell<Self>>,
1107 node_id: NodeId,
1108 snapshot: LayoutNodeSnapshot,
1109 constraints: Constraints,
1110 ) -> Result<Rc<MeasuredNode>, NodeError> {
1111 let cache_epoch = {
1112 let state = state_rc.borrow();
1113 state.cache_epoch
1114 };
1115 let LayoutNodeSnapshot {
1116 resolved_modifiers,
1117 measure_policy,
1118 children,
1119 cache,
1120 needs_measure,
1121 } = snapshot;
1122 cache.activate(cache_epoch);
1123 let layout_props = resolved_modifiers.layout_properties();
1124
1125 if needs_measure {
1126 }
1128
1129 if !needs_measure {
1133 if let Some(cached) = cache.get_measurement(constraints) {
1135 Self::with_applier_result(&state_rc, |applier| {
1137 applier.with_node::<LayoutNode, _>(node_id, |node| {
1138 node.clear_needs_measure();
1139 node.clear_needs_layout();
1140 })
1141 })
1142 .ok();
1143 return Ok(cached);
1144 }
1145 }
1146
1147 let (runtime_handle, applier_host) = {
1148 let state = state_rc.borrow();
1149 (state.runtime_handle.clone(), Rc::clone(&state.applier))
1150 };
1151
1152 let measure_handle = LayoutMeasureHandle::new(Rc::clone(&state_rc));
1153 let error = Rc::new(RefCell::new(None));
1154 let mut pools = VecPools::acquire(Rc::clone(&state_rc));
1155 let (measurables, records) = pools.parts();
1156
1157 for &child_id in children.iter() {
1158 let measured = Rc::new(RefCell::new(None));
1159 let position = Rc::new(RefCell::new(None));
1160
1161 let data = {
1162 let mut applier = applier_host.borrow_typed();
1163 match applier.with_node::<LayoutNode, _>(child_id, |n| {
1164 (n.cache_handles(), n.layout_state_handle())
1165 }) {
1166 Ok((cache, state)) => Some((cache, Some(state))),
1167 Err(NodeError::TypeMismatch { .. }) => {
1168 Some((LayoutNodeCacheHandles::default(), None))
1169 }
1170 Err(NodeError::Missing { .. }) => None,
1171 Err(err) => return Err(err),
1172 }
1173 };
1174
1175 let Some((cache_handles, layout_state)) = data else {
1176 continue;
1177 };
1178
1179 cache_handles.activate(cache_epoch);
1180
1181 records.push((
1182 child_id,
1183 ChildRecord {
1184 measured: Rc::clone(&measured),
1185 last_position: Rc::clone(&position),
1186 },
1187 ));
1188 measurables.push(Box::new(LayoutChildMeasurable::new(
1189 Rc::clone(&applier_host),
1190 child_id,
1191 measured,
1192 position,
1193 Rc::clone(&error),
1194 runtime_handle.clone(),
1195 cache_handles,
1196 cache_epoch,
1197 Some(measure_handle.clone()),
1198 layout_state,
1199 )));
1200 }
1201
1202 let chain_constraints = Constraints {
1204 min_width: constraints.min_width,
1205 max_width: if matches!(layout_props.width(), DimensionConstraint::Unspecified) {
1206 f32::INFINITY
1207 } else {
1208 constraints.max_width
1209 },
1210 min_height: constraints.min_height,
1211 max_height: if matches!(layout_props.height(), DimensionConstraint::Unspecified) {
1212 f32::INFINITY
1213 } else {
1214 constraints.max_height
1215 },
1216 };
1217
1218 let mut modifier_chain_result = Self::measure_through_modifier_chain(
1219 &state_rc,
1220 node_id,
1221 measurables.as_slice(),
1222 &measure_policy,
1223 chain_constraints,
1224 );
1225
1226 if (chain_constraints.max_width != constraints.max_width
1227 || chain_constraints.max_height != constraints.max_height)
1228 && ((constraints.max_width.is_finite()
1229 && modifier_chain_result.result.size.width > constraints.max_width)
1230 || (constraints.max_height.is_finite()
1231 && modifier_chain_result.result.size.height > constraints.max_height))
1232 {
1233 modifier_chain_result = Self::measure_through_modifier_chain(
1234 &state_rc,
1235 node_id,
1236 measurables.as_slice(),
1237 &measure_policy,
1238 constraints,
1239 );
1240 }
1241
1242 let (width, height, policy_result, content_offset, offset) = {
1244 let result = modifier_chain_result;
1245 if let Some(err) = error.borrow_mut().take() {
1248 return Err(err);
1249 }
1250
1251 (
1252 result.result.size.width,
1253 result.result.size.height,
1254 result.result,
1255 result.content_offset,
1256 result.offset,
1257 )
1258 };
1259
1260 let mut measured_children = Vec::new();
1261 for &child_id in children.iter() {
1262 if let Some((_, record)) = records.iter().find(|(id, _)| *id == child_id) {
1263 if let Some(measured) = record.measured.borrow_mut().take() {
1264 let base_position = policy_result
1265 .placements
1266 .iter()
1267 .find(|placement| placement.node_id == child_id)
1268 .map(|placement| Point {
1269 x: placement.x,
1270 y: placement.y,
1271 })
1272 .or_else(|| record.last_position.borrow().as_ref().copied())
1273 .unwrap_or(Point { x: 0.0, y: 0.0 });
1274 let position = Point {
1276 x: content_offset.x + base_position.x,
1277 y: content_offset.y + base_position.y,
1278 };
1279 measured_children.push(MeasuredChild {
1280 node: measured,
1281 offset: position,
1282 });
1283 }
1284 }
1285 }
1286
1287 let measured = Rc::new(MeasuredNode::new(
1288 node_id,
1289 Size { width, height },
1290 offset,
1291 content_offset,
1292 measured_children,
1293 ));
1294
1295 cache.store_measurement(constraints, Rc::clone(&measured));
1296
1297 Self::with_applier_result(&state_rc, |applier| {
1299 applier.with_node::<LayoutNode, _>(node_id, |node| {
1300 node.clear_needs_measure();
1301 node.clear_needs_layout();
1302 node.set_measured_size(Size { width, height });
1303 node.set_content_offset(content_offset);
1304 })
1305 })
1306 .ok();
1307
1308 Ok(measured)
1309 }
1310}
1311
1312struct LayoutNodeSnapshot {
1319 resolved_modifiers: ResolvedModifiers,
1320 measure_policy: Rc<dyn MeasurePolicy>,
1321 children: Vec<NodeId>,
1322 cache: LayoutNodeCacheHandles,
1323 needs_measure: bool,
1325}
1326
1327impl LayoutNodeSnapshot {
1328 fn from_layout_node(node: &LayoutNode) -> Self {
1329 Self {
1330 resolved_modifiers: node.resolved_modifiers(),
1331 measure_policy: Rc::clone(&node.measure_policy),
1332 children: node.children.iter().copied().collect(),
1333 cache: node.cache_handles(),
1334 needs_measure: node.needs_measure(),
1335 }
1336 }
1337}
1338
1339struct VecPools {
1341 state: Rc<RefCell<LayoutBuilderState>>,
1342 measurables: Option<Vec<Box<dyn Measurable>>>,
1343 records: Option<Vec<(NodeId, ChildRecord)>>,
1344}
1345
1346impl VecPools {
1347 fn acquire(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1348 let measurables = {
1349 let mut state_mut = state.borrow_mut();
1350 std::mem::take(&mut state_mut.tmp_measurables)
1351 };
1352 let records = {
1353 let mut state_mut = state.borrow_mut();
1354 std::mem::take(&mut state_mut.tmp_records)
1355 };
1356 Self {
1357 state,
1358 measurables: Some(measurables),
1359 records: Some(records),
1360 }
1361 }
1362
1363 #[allow(clippy::type_complexity)] fn parts(
1365 &mut self,
1366 ) -> (
1367 &mut Vec<Box<dyn Measurable>>,
1368 &mut Vec<(NodeId, ChildRecord)>,
1369 ) {
1370 let measurables = self
1371 .measurables
1372 .as_mut()
1373 .expect("measurables already returned");
1374 let records = self.records.as_mut().expect("records already returned");
1375 (measurables, records)
1376 }
1377}
1378
1379impl Drop for VecPools {
1380 fn drop(&mut self) {
1381 let mut state = self.state.borrow_mut();
1382 if let Some(mut measurables) = self.measurables.take() {
1383 measurables.clear();
1384 state.tmp_measurables = measurables;
1385 }
1386 if let Some(mut records) = self.records.take() {
1387 records.clear();
1388 state.tmp_records = records;
1389 }
1390 }
1391}
1392
1393struct SlotsGuard {
1394 state: Rc<RefCell<LayoutBuilderState>>,
1395 slots: Option<SlotBackend>,
1396}
1397
1398impl SlotsGuard {
1399 fn take(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1400 let slots = {
1401 let state_ref = state.borrow();
1402 let mut slots_ref = state_ref.slots.borrow_mut();
1403 std::mem::take(&mut *slots_ref)
1404 };
1405 Self {
1406 state,
1407 slots: Some(slots),
1408 }
1409 }
1410
1411 fn host(&mut self) -> Rc<SlotsHost> {
1412 let slots = self.slots.take().unwrap_or_default();
1413 Rc::new(SlotsHost::new(slots))
1414 }
1415
1416 fn restore(&mut self, slots: SlotBackend) {
1417 debug_assert!(self.slots.is_none());
1418 self.slots = Some(slots);
1419 }
1420}
1421
1422impl Drop for SlotsGuard {
1423 fn drop(&mut self) {
1424 if let Some(slots) = self.slots.take() {
1425 let state_ref = self.state.borrow();
1426 *state_ref.slots.borrow_mut() = slots;
1427 }
1428 }
1429}
1430
1431#[derive(Clone)]
1432struct LayoutMeasureHandle {
1433 state: Rc<RefCell<LayoutBuilderState>>,
1434}
1435
1436impl LayoutMeasureHandle {
1437 fn new(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1438 Self { state }
1439 }
1440
1441 fn measure(
1442 &self,
1443 node_id: NodeId,
1444 constraints: Constraints,
1445 ) -> Result<Rc<MeasuredNode>, NodeError> {
1446 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
1447 }
1448}
1449
1450#[derive(Debug, Clone)]
1451pub(crate) struct MeasuredNode {
1452 node_id: NodeId,
1453 size: Size,
1454 offset: Point,
1456 content_offset: Point,
1458 children: Vec<MeasuredChild>,
1459}
1460
1461impl MeasuredNode {
1462 fn new(
1463 node_id: NodeId,
1464 size: Size,
1465 offset: Point,
1466 content_offset: Point,
1467 children: Vec<MeasuredChild>,
1468 ) -> Self {
1469 Self {
1470 node_id,
1471 size,
1472 offset,
1473 content_offset,
1474 children,
1475 }
1476 }
1477}
1478
1479#[derive(Debug, Clone)]
1480struct MeasuredChild {
1481 node: Rc<MeasuredNode>,
1482 offset: Point,
1483}
1484
1485struct ChildRecord {
1486 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1487 last_position: Rc<RefCell<Option<Point>>>,
1488}
1489
1490struct LayoutChildMeasurable {
1491 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1492 node_id: NodeId,
1493 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1494 last_position: Rc<RefCell<Option<Point>>>,
1495 error: Rc<RefCell<Option<NodeError>>>,
1496 runtime_handle: Option<RuntimeHandle>,
1497 cache: LayoutNodeCacheHandles,
1498 cache_epoch: u64,
1499 measure_handle: Option<LayoutMeasureHandle>,
1500 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1501}
1502
1503impl LayoutChildMeasurable {
1504 #[allow(clippy::too_many_arguments)] fn new(
1506 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1507 node_id: NodeId,
1508 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1509 last_position: Rc<RefCell<Option<Point>>>,
1510 error: Rc<RefCell<Option<NodeError>>>,
1511 runtime_handle: Option<RuntimeHandle>,
1512 cache: LayoutNodeCacheHandles,
1513 cache_epoch: u64,
1514 measure_handle: Option<LayoutMeasureHandle>,
1515 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1516 ) -> Self {
1517 cache.activate(cache_epoch);
1518 Self {
1519 applier,
1520 node_id,
1521 measured,
1522 last_position,
1523 error,
1524 runtime_handle,
1525 cache,
1526 cache_epoch,
1527 measure_handle,
1528 layout_state,
1529 }
1530 }
1531
1532 fn record_error(&self, err: NodeError) {
1533 let mut slot = self.error.borrow_mut();
1534 if slot.is_none() {
1535 *slot = Some(err);
1536 }
1537 }
1538
1539 fn perform_measure(&self, constraints: Constraints) -> Result<Rc<MeasuredNode>, NodeError> {
1540 if let Some(handle) = &self.measure_handle {
1541 handle.measure(self.node_id, constraints)
1542 } else {
1543 measure_node_with_host(
1544 Rc::clone(&self.applier),
1545 self.runtime_handle.clone(),
1546 self.node_id,
1547 constraints,
1548 self.cache_epoch,
1549 )
1550 }
1551 }
1552
1553 fn intrinsic_measure(&self, constraints: Constraints) -> Option<Rc<MeasuredNode>> {
1554 self.cache.activate(self.cache_epoch);
1555 if let Some(cached) = self.cache.get_measurement(constraints) {
1556 return Some(cached);
1557 }
1558
1559 match self.perform_measure(constraints) {
1560 Ok(measured) => {
1561 self.cache
1562 .store_measurement(constraints, Rc::clone(&measured));
1563 Some(measured)
1564 }
1565 Err(err) => {
1566 self.record_error(err);
1567 None
1568 }
1569 }
1570 }
1571}
1572
1573impl Measurable for LayoutChildMeasurable {
1574 fn measure(&self, constraints: Constraints) -> Box<dyn Placeable> {
1575 self.cache.activate(self.cache_epoch);
1576 let measured_size;
1577 if let Some(cached) = self.cache.get_measurement(constraints) {
1578 measured_size = cached.size;
1579 *self.measured.borrow_mut() = Some(Rc::clone(&cached));
1580 } else {
1581 match self.perform_measure(constraints) {
1582 Ok(measured) => {
1583 measured_size = measured.size;
1584 self.cache
1585 .store_measurement(constraints, Rc::clone(&measured));
1586 *self.measured.borrow_mut() = Some(measured);
1587 }
1588 Err(err) => {
1589 self.record_error(err);
1590 self.measured.borrow_mut().take();
1591 measured_size = Size {
1592 width: 0.0,
1593 height: 0.0,
1594 };
1595 }
1596 }
1597 }
1598
1599 if let Some(state) = &self.layout_state {
1602 let mut state = state.borrow_mut();
1603 state.size = measured_size;
1604 state.measurement_constraints = constraints;
1605 } else if let Ok(mut applier) = self.applier.try_borrow_typed() {
1606 let _ = applier.with_node::<LayoutNode, _>(self.node_id, |node| {
1607 node.set_measured_size(measured_size);
1608 node.set_measurement_constraints(constraints);
1609 });
1610 }
1611
1612 Box::new(LayoutChildPlaceable::new(
1613 Rc::clone(&self.applier),
1614 self.node_id,
1615 Rc::clone(&self.measured),
1616 Rc::clone(&self.last_position),
1617 self.layout_state.clone(),
1618 ))
1619 }
1620
1621 fn min_intrinsic_width(&self, height: f32) -> f32 {
1622 let kind = IntrinsicKind::MinWidth(height);
1623 self.cache.activate(self.cache_epoch);
1624 if let Some(value) = self.cache.get_intrinsic(&kind) {
1625 return value;
1626 }
1627 let constraints = Constraints {
1628 min_width: 0.0,
1629 max_width: f32::INFINITY,
1630 min_height: height,
1631 max_height: height,
1632 };
1633 if let Some(node) = self.intrinsic_measure(constraints) {
1634 let value = node.size.width;
1635 self.cache.store_intrinsic(kind, value);
1636 value
1637 } else {
1638 0.0
1639 }
1640 }
1641
1642 fn max_intrinsic_width(&self, height: f32) -> f32 {
1643 let kind = IntrinsicKind::MaxWidth(height);
1644 self.cache.activate(self.cache_epoch);
1645 if let Some(value) = self.cache.get_intrinsic(&kind) {
1646 return value;
1647 }
1648 let constraints = Constraints {
1649 min_width: 0.0,
1650 max_width: f32::INFINITY,
1651 min_height: 0.0,
1652 max_height: height,
1653 };
1654 if let Some(node) = self.intrinsic_measure(constraints) {
1655 let value = node.size.width;
1656 self.cache.store_intrinsic(kind, value);
1657 value
1658 } else {
1659 0.0
1660 }
1661 }
1662
1663 fn min_intrinsic_height(&self, width: f32) -> f32 {
1664 let kind = IntrinsicKind::MinHeight(width);
1665 self.cache.activate(self.cache_epoch);
1666 if let Some(value) = self.cache.get_intrinsic(&kind) {
1667 return value;
1668 }
1669 let constraints = Constraints {
1670 min_width: width,
1671 max_width: width,
1672 min_height: 0.0,
1673 max_height: f32::INFINITY,
1674 };
1675 if let Some(node) = self.intrinsic_measure(constraints) {
1676 let value = node.size.height;
1677 self.cache.store_intrinsic(kind, value);
1678 value
1679 } else {
1680 0.0
1681 }
1682 }
1683
1684 fn max_intrinsic_height(&self, width: f32) -> f32 {
1685 let kind = IntrinsicKind::MaxHeight(width);
1686 self.cache.activate(self.cache_epoch);
1687 if let Some(value) = self.cache.get_intrinsic(&kind) {
1688 return value;
1689 }
1690 let constraints = Constraints {
1691 min_width: 0.0,
1692 max_width: width,
1693 min_height: 0.0,
1694 max_height: f32::INFINITY,
1695 };
1696 if let Some(node) = self.intrinsic_measure(constraints) {
1697 let value = node.size.height;
1698 self.cache.store_intrinsic(kind, value);
1699 value
1700 } else {
1701 0.0
1702 }
1703 }
1704
1705 fn flex_parent_data(&self) -> Option<cranpose_ui_layout::FlexParentData> {
1706 let Ok(mut applier) = self.applier.try_borrow_typed() else {
1709 return None;
1710 };
1711
1712 applier
1713 .with_node::<LayoutNode, _>(self.node_id, |layout_node| {
1714 let props = layout_node.resolved_modifiers().layout_properties();
1715 props.weight().map(|weight_data| {
1716 cranpose_ui_layout::FlexParentData::new(weight_data.weight, weight_data.fill)
1717 })
1718 })
1719 .ok()
1720 .flatten()
1721 }
1722}
1723
1724struct LayoutChildPlaceable {
1725 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1726 node_id: NodeId,
1727 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1728 last_position: Rc<RefCell<Option<Point>>>,
1729 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1730}
1731
1732impl LayoutChildPlaceable {
1733 fn new(
1734 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1735 node_id: NodeId,
1736 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1737 last_position: Rc<RefCell<Option<Point>>>,
1738 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1739 ) -> Self {
1740 Self {
1741 applier,
1742 node_id,
1743 measured,
1744 last_position,
1745 layout_state,
1746 }
1747 }
1748}
1749
1750impl Placeable for LayoutChildPlaceable {
1751 fn place(&self, x: f32, y: f32) {
1752 let internal_offset = self
1755 .measured
1756 .borrow()
1757 .as_ref()
1758 .map(|m| m.offset)
1759 .unwrap_or_default();
1760
1761 let position = Point {
1762 x: x + internal_offset.x,
1763 y: y + internal_offset.y,
1764 };
1765 *self.last_position.borrow_mut() = Some(position);
1767
1768 if let Some(state) = &self.layout_state {
1771 let mut state = state.borrow_mut();
1772 state.position = position;
1773 state.is_placed = true;
1774 } else if let Ok(mut applier) = self.applier.try_borrow_typed() {
1775 if applier
1777 .with_node::<LayoutNode, _>(self.node_id, |node| {
1778 node.set_position(position);
1779 })
1780 .is_err()
1781 {
1782 let _ = applier.with_node::<SubcomposeLayoutNode, _>(self.node_id, |node| {
1783 node.set_position(position);
1784 });
1785 }
1786 }
1787 }
1788
1789 fn width(&self) -> f32 {
1790 self.measured
1791 .borrow()
1792 .as_ref()
1793 .map(|node| node.size.width)
1794 .unwrap_or(0.0)
1795 }
1796
1797 fn height(&self) -> f32 {
1798 self.measured
1799 .borrow()
1800 .as_ref()
1801 .map(|node| node.size.height)
1802 .unwrap_or(0.0)
1803 }
1804
1805 fn node_id(&self) -> NodeId {
1806 self.node_id
1807 }
1808}
1809
1810fn measure_node_with_host(
1811 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1812 runtime_handle: Option<RuntimeHandle>,
1813 node_id: NodeId,
1814 constraints: Constraints,
1815 epoch: u64,
1816) -> Result<Rc<MeasuredNode>, NodeError> {
1817 let runtime_handle = match runtime_handle {
1818 Some(handle) => Some(handle),
1819 None => applier.borrow_typed().runtime_handle(),
1820 };
1821 let mut builder = LayoutBuilder::new_with_epoch(
1822 applier,
1823 epoch,
1824 Rc::new(RefCell::new(SlotBackend::default())),
1825 );
1826 builder.set_runtime_handle(runtime_handle);
1827 builder.measure_node(node_id, constraints)
1828}
1829
1830#[derive(Clone)]
1831struct RuntimeNodeMetadata {
1832 modifier: Modifier,
1833 resolved_modifiers: ResolvedModifiers,
1834 modifier_slices: Rc<ModifierNodeSlices>,
1835 role: SemanticsRole,
1836 button_handler: Option<Rc<RefCell<dyn FnMut()>>>,
1837}
1838
1839impl Default for RuntimeNodeMetadata {
1840 fn default() -> Self {
1841 Self {
1842 modifier: Modifier::empty(),
1843 resolved_modifiers: ResolvedModifiers::default(),
1844 modifier_slices: Rc::default(),
1845 role: SemanticsRole::Unknown,
1846 button_handler: None,
1847 }
1848 }
1849}
1850
1851fn collect_runtime_metadata(
1852 applier: &mut MemoryApplier,
1853 node: &MeasuredNode,
1854) -> Result<HashMap<NodeId, RuntimeNodeMetadata>, NodeError> {
1855 let mut map = HashMap::default();
1856 collect_runtime_metadata_inner(applier, node, &mut map)?;
1857 Ok(map)
1858}
1859
1860fn collect_semantics_with_owner(
1862 applier: &mut MemoryApplier,
1863 node: &MeasuredNode,
1864 owner: &SemanticsOwner,
1865) -> Result<(), NodeError> {
1866 owner.get_or_compute(node.node_id, applier);
1868
1869 for child in &node.children {
1871 collect_semantics_with_owner(applier, &child.node, owner)?;
1872 }
1873 Ok(())
1874}
1875
1876fn collect_semantics_snapshot(
1877 applier: &mut MemoryApplier,
1878 node: &MeasuredNode,
1879) -> Result<HashMap<NodeId, Option<SemanticsConfiguration>>, NodeError> {
1880 let owner = SemanticsOwner::new();
1881 collect_semantics_with_owner(applier, node, &owner)?;
1882
1883 let mut map = HashMap::default();
1885 extract_configurations_recursive(node, &owner, &mut map);
1886 Ok(map)
1887}
1888
1889fn extract_configurations_recursive(
1890 node: &MeasuredNode,
1891 owner: &SemanticsOwner,
1892 map: &mut HashMap<NodeId, Option<SemanticsConfiguration>>,
1893) {
1894 if let Some(config) = owner.configurations.borrow().get(&node.node_id) {
1895 map.insert(node.node_id, config.clone());
1896 }
1897 for child in &node.children {
1898 extract_configurations_recursive(&child.node, owner, map);
1899 }
1900}
1901
1902fn collect_runtime_metadata_inner(
1903 applier: &mut MemoryApplier,
1904 node: &MeasuredNode,
1905 map: &mut HashMap<NodeId, RuntimeNodeMetadata>,
1906) -> Result<(), NodeError> {
1907 if let Entry::Vacant(entry) = map.entry(node.node_id) {
1908 let meta = runtime_metadata_for(applier, node.node_id)?;
1909 entry.insert(meta);
1910 }
1911 for child in &node.children {
1912 collect_runtime_metadata_inner(applier, &child.node, map)?;
1913 }
1914 Ok(())
1915}
1916
1917fn extract_text_from_layout_node(layout: &LayoutNode) -> Option<String> {
1925 layout
1928 .semantics_configuration()
1929 .and_then(|config| config.content_description)
1930}
1931
1932fn runtime_metadata_for(
1933 applier: &mut MemoryApplier,
1934 node_id: NodeId,
1935) -> Result<RuntimeNodeMetadata, NodeError> {
1936 if let Ok(meta) = applier.with_node::<LayoutNode, _>(node_id, |layout| {
1941 let role = if let Some(text) = extract_text_from_layout_node(layout) {
1943 SemanticsRole::Text { value: text }
1944 } else {
1945 SemanticsRole::Layout
1946 };
1947
1948 RuntimeNodeMetadata {
1949 modifier: layout.modifier.clone(),
1950 resolved_modifiers: layout.resolved_modifiers(),
1951 modifier_slices: layout.modifier_slices_snapshot(),
1952 role,
1953 button_handler: None,
1954 }
1955 }) {
1956 return Ok(meta);
1957 }
1958
1959 if let Ok((modifier, resolved_modifiers)) = applier
1961 .with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1962 (node.modifier(), node.resolved_modifiers())
1963 })
1964 {
1965 let modifier_slices = Rc::new(collect_slices_from_modifier(&modifier));
1968 return Ok(RuntimeNodeMetadata {
1969 modifier,
1970 resolved_modifiers,
1971 modifier_slices,
1972 role: SemanticsRole::Subcompose,
1973 button_handler: None,
1974 });
1975 }
1976 Ok(RuntimeNodeMetadata::default())
1977}
1978
1979fn compute_semantics_for_node(
1983 applier: &mut MemoryApplier,
1984 node_id: NodeId,
1985) -> Option<SemanticsConfiguration> {
1986 match applier.with_node::<LayoutNode, _>(node_id, |layout| {
1988 let config = layout.semantics_configuration();
1989 layout.clear_needs_semantics();
1990 config
1991 }) {
1992 Ok(config) => return config,
1993 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {}
1994 Err(_) => return None,
1995 }
1996
1997 if let Ok(modifier) =
1999 applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| node.modifier())
2000 {
2001 return collect_semantics_from_modifier(&modifier);
2002 }
2003
2004 None
2005}
2006
2007fn build_semantics_node(
2011 node: &MeasuredNode,
2012 metadata: &HashMap<NodeId, RuntimeNodeMetadata>,
2013 semantics: &HashMap<NodeId, Option<SemanticsConfiguration>>,
2014) -> SemanticsNode {
2015 let info = metadata.get(&node.node_id).cloned().unwrap_or_default();
2016
2017 let mut role = info.role.clone();
2019 let mut actions = Vec::new();
2020 let mut description = None;
2021
2022 if let Some(config) = semantics.get(&node.node_id).cloned().flatten() {
2024 if config.is_button {
2026 role = SemanticsRole::Button;
2027 }
2028
2029 if config.is_clickable {
2031 actions.push(SemanticsAction::Click {
2032 handler: SemanticsCallback::new(node.node_id),
2033 });
2034 }
2035
2036 if let Some(desc) = config.content_description {
2038 description = Some(desc);
2039 }
2040 }
2041
2042 let children = node
2043 .children
2044 .iter()
2045 .map(|child| build_semantics_node(&child.node, metadata, semantics))
2046 .collect();
2047
2048 SemanticsNode::new(node.node_id, role, actions, children, description)
2049}
2050
2051fn build_layout_tree_from_metadata(
2052 node: &MeasuredNode,
2053 metadata: &HashMap<NodeId, RuntimeNodeMetadata>,
2054) -> LayoutTree {
2055 fn place(
2056 node: &MeasuredNode,
2057 origin: Point,
2058 metadata: &HashMap<NodeId, RuntimeNodeMetadata>,
2059 ) -> LayoutBox {
2060 let top_left = Point {
2062 x: origin.x + node.offset.x,
2063 y: origin.y + node.offset.y,
2064 };
2065 let rect = GeometryRect {
2066 x: top_left.x,
2067 y: top_left.y,
2068 width: node.size.width,
2069 height: node.size.height,
2070 };
2071 let info = metadata.get(&node.node_id).cloned().unwrap_or_default();
2072 let kind = layout_kind_from_metadata(node.node_id, &info);
2073 let data = LayoutNodeData::new(
2074 info.modifier.clone(),
2075 info.resolved_modifiers,
2076 info.modifier_slices.clone(),
2077 kind,
2078 );
2079 let children = node
2080 .children
2081 .iter()
2082 .map(|child| {
2083 let child_origin = Point {
2084 x: top_left.x + child.offset.x,
2085 y: top_left.y + child.offset.y,
2086 };
2087 place(&child.node, child_origin, metadata)
2088 })
2089 .collect();
2090 LayoutBox::new(node.node_id, rect, node.content_offset, data, children)
2091 }
2092
2093 LayoutTree::new(place(node, Point { x: 0.0, y: 0.0 }, metadata))
2094}
2095
2096fn layout_kind_from_metadata(_node_id: NodeId, info: &RuntimeNodeMetadata) -> LayoutNodeKind {
2097 match &info.role {
2098 SemanticsRole::Layout => LayoutNodeKind::Layout,
2099 SemanticsRole::Subcompose => LayoutNodeKind::Subcompose,
2100 SemanticsRole::Text { .. } => {
2101 LayoutNodeKind::Layout
2105 }
2106 SemanticsRole::Spacer => LayoutNodeKind::Spacer,
2107 SemanticsRole::Button => {
2108 let handler = info
2109 .button_handler
2110 .as_ref()
2111 .cloned()
2112 .unwrap_or_else(|| Rc::new(RefCell::new(|| {})));
2113 LayoutNodeKind::Button { on_click: handler }
2114 }
2115 SemanticsRole::Unknown => LayoutNodeKind::Unknown,
2116 }
2117}
2118
2119fn subtract_padding(constraints: Constraints, padding: EdgeInsets) -> Constraints {
2120 let horizontal = padding.horizontal_sum();
2121 let vertical = padding.vertical_sum();
2122 let min_width = (constraints.min_width - horizontal).max(0.0);
2123 let mut max_width = constraints.max_width;
2124 if max_width.is_finite() {
2125 max_width = (max_width - horizontal).max(0.0);
2126 }
2127 let min_height = (constraints.min_height - vertical).max(0.0);
2128 let mut max_height = constraints.max_height;
2129 if max_height.is_finite() {
2130 max_height = (max_height - vertical).max(0.0);
2131 }
2132 normalize_constraints(Constraints {
2133 min_width,
2134 max_width,
2135 min_height,
2136 max_height,
2137 })
2138}
2139
2140#[cfg(test)]
2141pub(crate) fn align_horizontal(alignment: HorizontalAlignment, available: f32, child: f32) -> f32 {
2142 match alignment {
2143 HorizontalAlignment::Start => 0.0,
2144 HorizontalAlignment::CenterHorizontally => ((available - child) / 2.0).max(0.0),
2145 HorizontalAlignment::End => (available - child).max(0.0),
2146 }
2147}
2148
2149#[cfg(test)]
2150pub(crate) fn align_vertical(alignment: VerticalAlignment, available: f32, child: f32) -> f32 {
2151 match alignment {
2152 VerticalAlignment::Top => 0.0,
2153 VerticalAlignment::CenterVertically => ((available - child) / 2.0).max(0.0),
2154 VerticalAlignment::Bottom => (available - child).max(0.0),
2155 }
2156}
2157
2158fn resolve_dimension(
2159 base: f32,
2160 explicit: DimensionConstraint,
2161 min_override: Option<f32>,
2162 max_override: Option<f32>,
2163 min_limit: f32,
2164 max_limit: f32,
2165) -> f32 {
2166 let mut min_bound = min_limit;
2167 if let Some(min_value) = min_override {
2168 min_bound = min_bound.max(min_value);
2169 }
2170
2171 let mut max_bound = if max_limit.is_finite() {
2172 max_limit
2173 } else {
2174 max_override.unwrap_or(max_limit)
2175 };
2176 if let Some(max_value) = max_override {
2177 if max_bound.is_finite() {
2178 max_bound = max_bound.min(max_value);
2179 } else {
2180 max_bound = max_value;
2181 }
2182 }
2183 if max_bound < min_bound {
2184 max_bound = min_bound;
2185 }
2186
2187 let mut size = match explicit {
2188 DimensionConstraint::Points(points) => points,
2189 DimensionConstraint::Fraction(fraction) => {
2190 if max_limit.is_finite() {
2191 max_limit * fraction.clamp(0.0, 1.0)
2192 } else {
2193 base
2194 }
2195 }
2196 DimensionConstraint::Unspecified => base,
2197 DimensionConstraint::Intrinsic(_) => base,
2200 };
2201
2202 size = clamp_dimension(size, min_bound, max_bound);
2203 size = clamp_dimension(size, min_limit, max_limit);
2204 size.max(0.0)
2205}
2206
2207fn clamp_dimension(value: f32, min: f32, max: f32) -> f32 {
2208 let mut result = value.max(min);
2209 if max.is_finite() {
2210 result = result.min(max);
2211 }
2212 result
2213}
2214
2215fn normalize_constraints(mut constraints: Constraints) -> Constraints {
2216 if constraints.max_width < constraints.min_width {
2217 constraints.max_width = constraints.min_width;
2218 }
2219 if constraints.max_height < constraints.min_height {
2220 constraints.max_height = constraints.min_height;
2221 }
2222 constraints
2223}
2224
2225#[cfg(test)]
2226#[path = "tests/layout_tests.rs"]
2227mod tests;