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 if layout_node_data.is_empty() {
1018 let result = measure_policy.measure(measurables, constraints);
1019 let final_size = result.size;
1020 let placements = result.placements;
1021
1022 return ModifierChainMeasurement {
1023 result: MeasureResult {
1024 size: final_size,
1025 placements,
1026 },
1027 content_offset: Point::default(),
1028 offset,
1029 };
1030 }
1031
1032 layout_node_data.reverse();
1035
1036 let shared_context = Rc::new(RefCell::new(LayoutNodeContext::new()));
1038
1039 let policy_result = Rc::new(RefCell::new(None));
1041 let inner_coordinator: Box<dyn NodeCoordinator + '_> =
1042 Box::new(coordinator::InnerCoordinator::new(
1043 Rc::clone(measure_policy),
1044 measurables,
1045 Rc::clone(&policy_result),
1046 ));
1047
1048 let mut current_coordinator = inner_coordinator;
1050 for (_, node_rc) in layout_node_data {
1051 current_coordinator = Box::new(coordinator::LayoutModifierCoordinator::new(
1052 node_rc,
1053 current_coordinator,
1054 Rc::clone(&shared_context),
1055 ));
1056 }
1057
1058 let placeable = current_coordinator.measure(constraints);
1060 let final_size = Size {
1061 width: placeable.width(),
1062 height: placeable.height(),
1063 };
1064
1065 let content_offset = placeable.content_offset();
1067 let all_placement_offset = Point {
1068 x: content_offset.0,
1069 y: content_offset.1,
1070 };
1071
1072 let content_offset = Point {
1076 x: all_placement_offset.x - offset.x,
1077 y: all_placement_offset.y - offset.y,
1078 };
1079
1080 let placements = policy_result
1083 .borrow_mut()
1084 .take()
1085 .map(|result| result.placements)
1086 .unwrap_or_default();
1087
1088 let invalidations = shared_context.borrow_mut().take_invalidations();
1090 if !invalidations.is_empty() {
1091 Self::with_applier_result(state_rc, |applier| {
1093 applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1094 for kind in invalidations {
1095 match kind {
1096 InvalidationKind::Layout => layout_node.mark_needs_measure(),
1097 InvalidationKind::Draw => layout_node.mark_needs_redraw(),
1098 InvalidationKind::Semantics => layout_node.mark_needs_semantics(),
1099 InvalidationKind::PointerInput => layout_node.mark_needs_pointer_pass(),
1100 InvalidationKind::Focus => layout_node.mark_needs_focus_sync(),
1101 }
1102 }
1103 })
1104 })
1105 .ok();
1106 }
1107
1108 ModifierChainMeasurement {
1109 result: MeasureResult {
1110 size: final_size,
1111 placements,
1112 },
1113 content_offset,
1114 offset,
1115 }
1116 }
1117
1118 fn measure_layout_node(
1119 state_rc: Rc<RefCell<Self>>,
1120 node_id: NodeId,
1121 snapshot: LayoutNodeSnapshot,
1122 constraints: Constraints,
1123 ) -> Result<Rc<MeasuredNode>, NodeError> {
1124 let cache_epoch = {
1125 let state = state_rc.borrow();
1126 state.cache_epoch
1127 };
1128 let LayoutNodeSnapshot {
1129 resolved_modifiers,
1130 measure_policy,
1131 children,
1132 cache,
1133 needs_measure,
1134 } = snapshot;
1135 cache.activate(cache_epoch);
1136 let layout_props = resolved_modifiers.layout_properties();
1137
1138 if needs_measure {
1139 }
1141
1142 if !needs_measure {
1146 if let Some(cached) = cache.get_measurement(constraints) {
1148 Self::with_applier_result(&state_rc, |applier| {
1150 applier.with_node::<LayoutNode, _>(node_id, |node| {
1151 node.clear_needs_measure();
1152 node.clear_needs_layout();
1153 })
1154 })
1155 .ok();
1156 return Ok(cached);
1157 }
1158 }
1159
1160 let (runtime_handle, applier_host) = {
1161 let state = state_rc.borrow();
1162 (state.runtime_handle.clone(), Rc::clone(&state.applier))
1163 };
1164
1165 let measure_handle = LayoutMeasureHandle::new(Rc::clone(&state_rc));
1166 let error = Rc::new(RefCell::new(None));
1167 let mut pools = VecPools::acquire(Rc::clone(&state_rc));
1168 let (measurables, records) = pools.parts();
1169
1170 for &child_id in children.iter() {
1171 let measured = Rc::new(RefCell::new(None));
1172 let position = Rc::new(RefCell::new(None));
1173
1174 let data = {
1175 let mut applier = applier_host.borrow_typed();
1176 match applier.with_node::<LayoutNode, _>(child_id, |n| {
1177 (n.cache_handles(), n.layout_state_handle())
1178 }) {
1179 Ok((cache, state)) => Some((cache, Some(state))),
1180 Err(NodeError::TypeMismatch { .. }) => {
1181 Some((LayoutNodeCacheHandles::default(), None))
1182 }
1183 Err(NodeError::Missing { .. }) => None,
1184 Err(err) => return Err(err),
1185 }
1186 };
1187
1188 let Some((cache_handles, layout_state)) = data else {
1189 continue;
1190 };
1191
1192 cache_handles.activate(cache_epoch);
1193
1194 records.push((
1195 child_id,
1196 ChildRecord {
1197 measured: Rc::clone(&measured),
1198 last_position: Rc::clone(&position),
1199 },
1200 ));
1201 measurables.push(Box::new(LayoutChildMeasurable::new(
1202 Rc::clone(&applier_host),
1203 child_id,
1204 measured,
1205 position,
1206 Rc::clone(&error),
1207 runtime_handle.clone(),
1208 cache_handles,
1209 cache_epoch,
1210 Some(measure_handle.clone()),
1211 layout_state,
1212 )));
1213 }
1214
1215 let has_weight = layout_props
1220 .weight()
1221 .map(|weight| weight.weight > 0.0)
1222 .unwrap_or(false);
1223 let chain_constraints = if has_weight {
1224 constraints
1225 } else {
1226 Constraints {
1227 min_width: constraints.min_width,
1228 max_width: if matches!(layout_props.width(), DimensionConstraint::Unspecified) {
1229 f32::INFINITY
1230 } else {
1231 constraints.max_width
1232 },
1233 min_height: constraints.min_height,
1234 max_height: if matches!(layout_props.height(), DimensionConstraint::Unspecified) {
1235 f32::INFINITY
1236 } else {
1237 constraints.max_height
1238 },
1239 }
1240 };
1241
1242 let mut modifier_chain_result = Self::measure_through_modifier_chain(
1243 &state_rc,
1244 node_id,
1245 measurables.as_slice(),
1246 &measure_policy,
1247 chain_constraints,
1248 );
1249
1250 if (chain_constraints.max_width != constraints.max_width
1251 || chain_constraints.max_height != constraints.max_height)
1252 && ((constraints.max_width.is_finite()
1253 && modifier_chain_result.result.size.width > constraints.max_width)
1254 || (constraints.max_height.is_finite()
1255 && modifier_chain_result.result.size.height > constraints.max_height))
1256 {
1257 modifier_chain_result = Self::measure_through_modifier_chain(
1258 &state_rc,
1259 node_id,
1260 measurables.as_slice(),
1261 &measure_policy,
1262 constraints,
1263 );
1264 }
1265
1266 let (width, height, policy_result, content_offset, offset) = {
1268 let result = modifier_chain_result;
1269 if let Some(err) = error.borrow_mut().take() {
1272 return Err(err);
1273 }
1274
1275 (
1276 result.result.size.width,
1277 result.result.size.height,
1278 result.result,
1279 result.content_offset,
1280 result.offset,
1281 )
1282 };
1283
1284 let mut measured_children = Vec::new();
1285 for &child_id in children.iter() {
1286 if let Some((_, record)) = records.iter().find(|(id, _)| *id == child_id) {
1287 if let Some(measured) = record.measured.borrow_mut().take() {
1288 let base_position = policy_result
1289 .placements
1290 .iter()
1291 .find(|placement| placement.node_id == child_id)
1292 .map(|placement| Point {
1293 x: placement.x,
1294 y: placement.y,
1295 })
1296 .or_else(|| record.last_position.borrow().as_ref().copied())
1297 .unwrap_or(Point { x: 0.0, y: 0.0 });
1298 let position = Point {
1300 x: content_offset.x + base_position.x,
1301 y: content_offset.y + base_position.y,
1302 };
1303 measured_children.push(MeasuredChild {
1304 node: measured,
1305 offset: position,
1306 });
1307 }
1308 }
1309 }
1310
1311 let measured = Rc::new(MeasuredNode::new(
1312 node_id,
1313 Size { width, height },
1314 offset,
1315 content_offset,
1316 measured_children,
1317 ));
1318
1319 cache.store_measurement(constraints, Rc::clone(&measured));
1320
1321 Self::with_applier_result(&state_rc, |applier| {
1323 applier.with_node::<LayoutNode, _>(node_id, |node| {
1324 node.clear_needs_measure();
1325 node.clear_needs_layout();
1326 node.set_measured_size(Size { width, height });
1327 node.set_content_offset(content_offset);
1328 })
1329 })
1330 .ok();
1331
1332 Ok(measured)
1333 }
1334}
1335
1336struct LayoutNodeSnapshot {
1343 resolved_modifiers: ResolvedModifiers,
1344 measure_policy: Rc<dyn MeasurePolicy>,
1345 children: Vec<NodeId>,
1346 cache: LayoutNodeCacheHandles,
1347 needs_measure: bool,
1349}
1350
1351impl LayoutNodeSnapshot {
1352 fn from_layout_node(node: &LayoutNode) -> Self {
1353 Self {
1354 resolved_modifiers: node.resolved_modifiers(),
1355 measure_policy: Rc::clone(&node.measure_policy),
1356 children: node.children.iter().copied().collect(),
1357 cache: node.cache_handles(),
1358 needs_measure: node.needs_measure(),
1359 }
1360 }
1361}
1362
1363struct VecPools {
1365 state: Rc<RefCell<LayoutBuilderState>>,
1366 measurables: Option<Vec<Box<dyn Measurable>>>,
1367 records: Option<Vec<(NodeId, ChildRecord)>>,
1368}
1369
1370impl VecPools {
1371 fn acquire(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1372 let measurables = {
1373 let mut state_mut = state.borrow_mut();
1374 std::mem::take(&mut state_mut.tmp_measurables)
1375 };
1376 let records = {
1377 let mut state_mut = state.borrow_mut();
1378 std::mem::take(&mut state_mut.tmp_records)
1379 };
1380 Self {
1381 state,
1382 measurables: Some(measurables),
1383 records: Some(records),
1384 }
1385 }
1386
1387 #[allow(clippy::type_complexity)] fn parts(
1389 &mut self,
1390 ) -> (
1391 &mut Vec<Box<dyn Measurable>>,
1392 &mut Vec<(NodeId, ChildRecord)>,
1393 ) {
1394 let measurables = self
1395 .measurables
1396 .as_mut()
1397 .expect("measurables already returned");
1398 let records = self.records.as_mut().expect("records already returned");
1399 (measurables, records)
1400 }
1401}
1402
1403impl Drop for VecPools {
1404 fn drop(&mut self) {
1405 let mut state = self.state.borrow_mut();
1406 if let Some(mut measurables) = self.measurables.take() {
1407 measurables.clear();
1408 state.tmp_measurables = measurables;
1409 }
1410 if let Some(mut records) = self.records.take() {
1411 records.clear();
1412 state.tmp_records = records;
1413 }
1414 }
1415}
1416
1417struct SlotsGuard {
1418 state: Rc<RefCell<LayoutBuilderState>>,
1419 slots: Option<SlotBackend>,
1420}
1421
1422impl SlotsGuard {
1423 fn take(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1424 let slots = {
1425 let state_ref = state.borrow();
1426 let mut slots_ref = state_ref.slots.borrow_mut();
1427 std::mem::take(&mut *slots_ref)
1428 };
1429 Self {
1430 state,
1431 slots: Some(slots),
1432 }
1433 }
1434
1435 fn host(&mut self) -> Rc<SlotsHost> {
1436 let slots = self.slots.take().unwrap_or_default();
1437 Rc::new(SlotsHost::new(slots))
1438 }
1439
1440 fn restore(&mut self, slots: SlotBackend) {
1441 debug_assert!(self.slots.is_none());
1442 self.slots = Some(slots);
1443 }
1444}
1445
1446impl Drop for SlotsGuard {
1447 fn drop(&mut self) {
1448 if let Some(slots) = self.slots.take() {
1449 let state_ref = self.state.borrow();
1450 *state_ref.slots.borrow_mut() = slots;
1451 }
1452 }
1453}
1454
1455#[derive(Clone)]
1456struct LayoutMeasureHandle {
1457 state: Rc<RefCell<LayoutBuilderState>>,
1458}
1459
1460impl LayoutMeasureHandle {
1461 fn new(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1462 Self { state }
1463 }
1464
1465 fn measure(
1466 &self,
1467 node_id: NodeId,
1468 constraints: Constraints,
1469 ) -> Result<Rc<MeasuredNode>, NodeError> {
1470 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
1471 }
1472}
1473
1474#[derive(Debug, Clone)]
1475pub(crate) struct MeasuredNode {
1476 node_id: NodeId,
1477 size: Size,
1478 offset: Point,
1480 content_offset: Point,
1482 children: Vec<MeasuredChild>,
1483}
1484
1485impl MeasuredNode {
1486 fn new(
1487 node_id: NodeId,
1488 size: Size,
1489 offset: Point,
1490 content_offset: Point,
1491 children: Vec<MeasuredChild>,
1492 ) -> Self {
1493 Self {
1494 node_id,
1495 size,
1496 offset,
1497 content_offset,
1498 children,
1499 }
1500 }
1501}
1502
1503#[derive(Debug, Clone)]
1504struct MeasuredChild {
1505 node: Rc<MeasuredNode>,
1506 offset: Point,
1507}
1508
1509struct ChildRecord {
1510 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1511 last_position: Rc<RefCell<Option<Point>>>,
1512}
1513
1514struct LayoutChildMeasurable {
1515 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1516 node_id: NodeId,
1517 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1518 last_position: Rc<RefCell<Option<Point>>>,
1519 error: Rc<RefCell<Option<NodeError>>>,
1520 runtime_handle: Option<RuntimeHandle>,
1521 cache: LayoutNodeCacheHandles,
1522 cache_epoch: u64,
1523 measure_handle: Option<LayoutMeasureHandle>,
1524 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1525}
1526
1527impl LayoutChildMeasurable {
1528 #[allow(clippy::too_many_arguments)] fn new(
1530 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1531 node_id: NodeId,
1532 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1533 last_position: Rc<RefCell<Option<Point>>>,
1534 error: Rc<RefCell<Option<NodeError>>>,
1535 runtime_handle: Option<RuntimeHandle>,
1536 cache: LayoutNodeCacheHandles,
1537 cache_epoch: u64,
1538 measure_handle: Option<LayoutMeasureHandle>,
1539 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1540 ) -> Self {
1541 cache.activate(cache_epoch);
1542 Self {
1543 applier,
1544 node_id,
1545 measured,
1546 last_position,
1547 error,
1548 runtime_handle,
1549 cache,
1550 cache_epoch,
1551 measure_handle,
1552 layout_state,
1553 }
1554 }
1555
1556 fn record_error(&self, err: NodeError) {
1557 let mut slot = self.error.borrow_mut();
1558 if slot.is_none() {
1559 *slot = Some(err);
1560 }
1561 }
1562
1563 fn perform_measure(&self, constraints: Constraints) -> Result<Rc<MeasuredNode>, NodeError> {
1564 if let Some(handle) = &self.measure_handle {
1565 handle.measure(self.node_id, constraints)
1566 } else {
1567 measure_node_with_host(
1568 Rc::clone(&self.applier),
1569 self.runtime_handle.clone(),
1570 self.node_id,
1571 constraints,
1572 self.cache_epoch,
1573 )
1574 }
1575 }
1576
1577 fn intrinsic_measure(&self, constraints: Constraints) -> Option<Rc<MeasuredNode>> {
1578 self.cache.activate(self.cache_epoch);
1579 if let Some(cached) = self.cache.get_measurement(constraints) {
1580 return Some(cached);
1581 }
1582
1583 match self.perform_measure(constraints) {
1584 Ok(measured) => {
1585 self.cache
1586 .store_measurement(constraints, Rc::clone(&measured));
1587 Some(measured)
1588 }
1589 Err(err) => {
1590 self.record_error(err);
1591 None
1592 }
1593 }
1594 }
1595}
1596
1597impl Measurable for LayoutChildMeasurable {
1598 fn measure(&self, constraints: Constraints) -> Box<dyn Placeable> {
1599 self.cache.activate(self.cache_epoch);
1600 let measured_size;
1601 if let Some(cached) = self.cache.get_measurement(constraints) {
1602 measured_size = cached.size;
1603 *self.measured.borrow_mut() = Some(Rc::clone(&cached));
1604 } else {
1605 match self.perform_measure(constraints) {
1606 Ok(measured) => {
1607 measured_size = measured.size;
1608 self.cache
1609 .store_measurement(constraints, Rc::clone(&measured));
1610 *self.measured.borrow_mut() = Some(measured);
1611 }
1612 Err(err) => {
1613 self.record_error(err);
1614 self.measured.borrow_mut().take();
1615 measured_size = Size {
1616 width: 0.0,
1617 height: 0.0,
1618 };
1619 }
1620 }
1621 }
1622
1623 if let Some(state) = &self.layout_state {
1626 let mut state = state.borrow_mut();
1627 state.size = measured_size;
1628 state.measurement_constraints = constraints;
1629 } else if let Ok(mut applier) = self.applier.try_borrow_typed() {
1630 let _ = applier.with_node::<LayoutNode, _>(self.node_id, |node| {
1631 node.set_measured_size(measured_size);
1632 node.set_measurement_constraints(constraints);
1633 });
1634 }
1635
1636 Box::new(LayoutChildPlaceable::new(
1637 Rc::clone(&self.applier),
1638 self.node_id,
1639 Rc::clone(&self.measured),
1640 Rc::clone(&self.last_position),
1641 self.layout_state.clone(),
1642 ))
1643 }
1644
1645 fn min_intrinsic_width(&self, height: f32) -> f32 {
1646 let kind = IntrinsicKind::MinWidth(height);
1647 self.cache.activate(self.cache_epoch);
1648 if let Some(value) = self.cache.get_intrinsic(&kind) {
1649 return value;
1650 }
1651 let constraints = Constraints {
1652 min_width: 0.0,
1653 max_width: f32::INFINITY,
1654 min_height: height,
1655 max_height: height,
1656 };
1657 if let Some(node) = self.intrinsic_measure(constraints) {
1658 let value = node.size.width;
1659 self.cache.store_intrinsic(kind, value);
1660 value
1661 } else {
1662 0.0
1663 }
1664 }
1665
1666 fn max_intrinsic_width(&self, height: f32) -> f32 {
1667 let kind = IntrinsicKind::MaxWidth(height);
1668 self.cache.activate(self.cache_epoch);
1669 if let Some(value) = self.cache.get_intrinsic(&kind) {
1670 return value;
1671 }
1672 let constraints = Constraints {
1673 min_width: 0.0,
1674 max_width: f32::INFINITY,
1675 min_height: 0.0,
1676 max_height: height,
1677 };
1678 if let Some(node) = self.intrinsic_measure(constraints) {
1679 let value = node.size.width;
1680 self.cache.store_intrinsic(kind, value);
1681 value
1682 } else {
1683 0.0
1684 }
1685 }
1686
1687 fn min_intrinsic_height(&self, width: f32) -> f32 {
1688 let kind = IntrinsicKind::MinHeight(width);
1689 self.cache.activate(self.cache_epoch);
1690 if let Some(value) = self.cache.get_intrinsic(&kind) {
1691 return value;
1692 }
1693 let constraints = Constraints {
1694 min_width: width,
1695 max_width: width,
1696 min_height: 0.0,
1697 max_height: f32::INFINITY,
1698 };
1699 if let Some(node) = self.intrinsic_measure(constraints) {
1700 let value = node.size.height;
1701 self.cache.store_intrinsic(kind, value);
1702 value
1703 } else {
1704 0.0
1705 }
1706 }
1707
1708 fn max_intrinsic_height(&self, width: f32) -> f32 {
1709 let kind = IntrinsicKind::MaxHeight(width);
1710 self.cache.activate(self.cache_epoch);
1711 if let Some(value) = self.cache.get_intrinsic(&kind) {
1712 return value;
1713 }
1714 let constraints = Constraints {
1715 min_width: 0.0,
1716 max_width: width,
1717 min_height: 0.0,
1718 max_height: f32::INFINITY,
1719 };
1720 if let Some(node) = self.intrinsic_measure(constraints) {
1721 let value = node.size.height;
1722 self.cache.store_intrinsic(kind, value);
1723 value
1724 } else {
1725 0.0
1726 }
1727 }
1728
1729 fn flex_parent_data(&self) -> Option<cranpose_ui_layout::FlexParentData> {
1730 let Ok(mut applier) = self.applier.try_borrow_typed() else {
1733 return None;
1734 };
1735
1736 applier
1737 .with_node::<LayoutNode, _>(self.node_id, |layout_node| {
1738 let props = layout_node.resolved_modifiers().layout_properties();
1739 props.weight().map(|weight_data| {
1740 cranpose_ui_layout::FlexParentData::new(weight_data.weight, weight_data.fill)
1741 })
1742 })
1743 .ok()
1744 .flatten()
1745 }
1746}
1747
1748struct LayoutChildPlaceable {
1749 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1750 node_id: NodeId,
1751 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1752 last_position: Rc<RefCell<Option<Point>>>,
1753 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1754}
1755
1756impl LayoutChildPlaceable {
1757 fn new(
1758 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1759 node_id: NodeId,
1760 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1761 last_position: Rc<RefCell<Option<Point>>>,
1762 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1763 ) -> Self {
1764 Self {
1765 applier,
1766 node_id,
1767 measured,
1768 last_position,
1769 layout_state,
1770 }
1771 }
1772}
1773
1774impl Placeable for LayoutChildPlaceable {
1775 fn place(&self, x: f32, y: f32) {
1776 let internal_offset = self
1779 .measured
1780 .borrow()
1781 .as_ref()
1782 .map(|m| m.offset)
1783 .unwrap_or_default();
1784
1785 let position = Point {
1786 x: x + internal_offset.x,
1787 y: y + internal_offset.y,
1788 };
1789 *self.last_position.borrow_mut() = Some(position);
1791
1792 if let Some(state) = &self.layout_state {
1795 let mut state = state.borrow_mut();
1796 state.position = position;
1797 state.is_placed = true;
1798 } else if let Ok(mut applier) = self.applier.try_borrow_typed() {
1799 if applier
1801 .with_node::<LayoutNode, _>(self.node_id, |node| {
1802 node.set_position(position);
1803 })
1804 .is_err()
1805 {
1806 let _ = applier.with_node::<SubcomposeLayoutNode, _>(self.node_id, |node| {
1807 node.set_position(position);
1808 });
1809 }
1810 }
1811 }
1812
1813 fn width(&self) -> f32 {
1814 self.measured
1815 .borrow()
1816 .as_ref()
1817 .map(|node| node.size.width)
1818 .unwrap_or(0.0)
1819 }
1820
1821 fn height(&self) -> f32 {
1822 self.measured
1823 .borrow()
1824 .as_ref()
1825 .map(|node| node.size.height)
1826 .unwrap_or(0.0)
1827 }
1828
1829 fn node_id(&self) -> NodeId {
1830 self.node_id
1831 }
1832}
1833
1834fn measure_node_with_host(
1835 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1836 runtime_handle: Option<RuntimeHandle>,
1837 node_id: NodeId,
1838 constraints: Constraints,
1839 epoch: u64,
1840) -> Result<Rc<MeasuredNode>, NodeError> {
1841 let runtime_handle = match runtime_handle {
1842 Some(handle) => Some(handle),
1843 None => applier.borrow_typed().runtime_handle(),
1844 };
1845 let mut builder = LayoutBuilder::new_with_epoch(
1846 applier,
1847 epoch,
1848 Rc::new(RefCell::new(SlotBackend::default())),
1849 );
1850 builder.set_runtime_handle(runtime_handle);
1851 builder.measure_node(node_id, constraints)
1852}
1853
1854#[derive(Clone)]
1855struct RuntimeNodeMetadata {
1856 modifier: Modifier,
1857 resolved_modifiers: ResolvedModifiers,
1858 modifier_slices: Rc<ModifierNodeSlices>,
1859 role: SemanticsRole,
1860 button_handler: Option<Rc<RefCell<dyn FnMut()>>>,
1861}
1862
1863impl Default for RuntimeNodeMetadata {
1864 fn default() -> Self {
1865 Self {
1866 modifier: Modifier::empty(),
1867 resolved_modifiers: ResolvedModifiers::default(),
1868 modifier_slices: Rc::default(),
1869 role: SemanticsRole::Unknown,
1870 button_handler: None,
1871 }
1872 }
1873}
1874
1875fn collect_runtime_metadata(
1876 applier: &mut MemoryApplier,
1877 node: &MeasuredNode,
1878) -> Result<HashMap<NodeId, RuntimeNodeMetadata>, NodeError> {
1879 let mut map = HashMap::default();
1880 collect_runtime_metadata_inner(applier, node, &mut map)?;
1881 Ok(map)
1882}
1883
1884fn collect_semantics_with_owner(
1886 applier: &mut MemoryApplier,
1887 node: &MeasuredNode,
1888 owner: &SemanticsOwner,
1889) -> Result<(), NodeError> {
1890 owner.get_or_compute(node.node_id, applier);
1892
1893 for child in &node.children {
1895 collect_semantics_with_owner(applier, &child.node, owner)?;
1896 }
1897 Ok(())
1898}
1899
1900fn collect_semantics_snapshot(
1901 applier: &mut MemoryApplier,
1902 node: &MeasuredNode,
1903) -> Result<HashMap<NodeId, Option<SemanticsConfiguration>>, NodeError> {
1904 let owner = SemanticsOwner::new();
1905 collect_semantics_with_owner(applier, node, &owner)?;
1906
1907 let mut map = HashMap::default();
1909 extract_configurations_recursive(node, &owner, &mut map);
1910 Ok(map)
1911}
1912
1913fn extract_configurations_recursive(
1914 node: &MeasuredNode,
1915 owner: &SemanticsOwner,
1916 map: &mut HashMap<NodeId, Option<SemanticsConfiguration>>,
1917) {
1918 if let Some(config) = owner.configurations.borrow().get(&node.node_id) {
1919 map.insert(node.node_id, config.clone());
1920 }
1921 for child in &node.children {
1922 extract_configurations_recursive(&child.node, owner, map);
1923 }
1924}
1925
1926fn collect_runtime_metadata_inner(
1927 applier: &mut MemoryApplier,
1928 node: &MeasuredNode,
1929 map: &mut HashMap<NodeId, RuntimeNodeMetadata>,
1930) -> Result<(), NodeError> {
1931 if let Entry::Vacant(entry) = map.entry(node.node_id) {
1932 let meta = runtime_metadata_for(applier, node.node_id)?;
1933 entry.insert(meta);
1934 }
1935 for child in &node.children {
1936 collect_runtime_metadata_inner(applier, &child.node, map)?;
1937 }
1938 Ok(())
1939}
1940
1941fn extract_text_from_layout_node(layout: &LayoutNode) -> Option<String> {
1949 layout
1952 .semantics_configuration()
1953 .and_then(|config| config.content_description)
1954}
1955
1956fn runtime_metadata_for(
1957 applier: &mut MemoryApplier,
1958 node_id: NodeId,
1959) -> Result<RuntimeNodeMetadata, NodeError> {
1960 if let Ok(meta) = applier.with_node::<LayoutNode, _>(node_id, |layout| {
1965 let role = if let Some(text) = extract_text_from_layout_node(layout) {
1967 SemanticsRole::Text { value: text }
1968 } else {
1969 SemanticsRole::Layout
1970 };
1971
1972 RuntimeNodeMetadata {
1973 modifier: layout.modifier.clone(),
1974 resolved_modifiers: layout.resolved_modifiers(),
1975 modifier_slices: layout.modifier_slices_snapshot(),
1976 role,
1977 button_handler: None,
1978 }
1979 }) {
1980 return Ok(meta);
1981 }
1982
1983 if let Ok((modifier, resolved_modifiers)) = applier
1985 .with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1986 (node.modifier(), node.resolved_modifiers())
1987 })
1988 {
1989 let modifier_slices = Rc::new(collect_slices_from_modifier(&modifier));
1992 return Ok(RuntimeNodeMetadata {
1993 modifier,
1994 resolved_modifiers,
1995 modifier_slices,
1996 role: SemanticsRole::Subcompose,
1997 button_handler: None,
1998 });
1999 }
2000 Ok(RuntimeNodeMetadata::default())
2001}
2002
2003fn compute_semantics_for_node(
2007 applier: &mut MemoryApplier,
2008 node_id: NodeId,
2009) -> Option<SemanticsConfiguration> {
2010 match applier.with_node::<LayoutNode, _>(node_id, |layout| {
2012 let config = layout.semantics_configuration();
2013 layout.clear_needs_semantics();
2014 config
2015 }) {
2016 Ok(config) => return config,
2017 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {}
2018 Err(_) => return None,
2019 }
2020
2021 if let Ok(modifier) =
2023 applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| node.modifier())
2024 {
2025 return collect_semantics_from_modifier(&modifier);
2026 }
2027
2028 None
2029}
2030
2031fn build_semantics_node(
2035 node: &MeasuredNode,
2036 metadata: &HashMap<NodeId, RuntimeNodeMetadata>,
2037 semantics: &HashMap<NodeId, Option<SemanticsConfiguration>>,
2038) -> SemanticsNode {
2039 let info = metadata.get(&node.node_id).cloned().unwrap_or_default();
2040
2041 let mut role = info.role.clone();
2043 let mut actions = Vec::new();
2044 let mut description = None;
2045
2046 if let Some(config) = semantics.get(&node.node_id).cloned().flatten() {
2048 if config.is_button {
2050 role = SemanticsRole::Button;
2051 }
2052
2053 if config.is_clickable {
2055 actions.push(SemanticsAction::Click {
2056 handler: SemanticsCallback::new(node.node_id),
2057 });
2058 }
2059
2060 if let Some(desc) = config.content_description {
2062 description = Some(desc);
2063 }
2064 }
2065
2066 let children = node
2067 .children
2068 .iter()
2069 .map(|child| build_semantics_node(&child.node, metadata, semantics))
2070 .collect();
2071
2072 SemanticsNode::new(node.node_id, role, actions, children, description)
2073}
2074
2075fn build_layout_tree_from_metadata(
2076 node: &MeasuredNode,
2077 metadata: &HashMap<NodeId, RuntimeNodeMetadata>,
2078) -> LayoutTree {
2079 fn place(
2080 node: &MeasuredNode,
2081 origin: Point,
2082 metadata: &HashMap<NodeId, RuntimeNodeMetadata>,
2083 ) -> LayoutBox {
2084 let top_left = Point {
2086 x: origin.x + node.offset.x,
2087 y: origin.y + node.offset.y,
2088 };
2089 let rect = GeometryRect {
2090 x: top_left.x,
2091 y: top_left.y,
2092 width: node.size.width,
2093 height: node.size.height,
2094 };
2095 let info = metadata.get(&node.node_id).cloned().unwrap_or_default();
2096 let kind = layout_kind_from_metadata(node.node_id, &info);
2097 let data = LayoutNodeData::new(
2098 info.modifier.clone(),
2099 info.resolved_modifiers,
2100 info.modifier_slices.clone(),
2101 kind,
2102 );
2103 let children = node
2104 .children
2105 .iter()
2106 .map(|child| {
2107 let child_origin = Point {
2108 x: top_left.x + child.offset.x,
2109 y: top_left.y + child.offset.y,
2110 };
2111 place(&child.node, child_origin, metadata)
2112 })
2113 .collect();
2114 LayoutBox::new(node.node_id, rect, node.content_offset, data, children)
2115 }
2116
2117 LayoutTree::new(place(node, Point { x: 0.0, y: 0.0 }, metadata))
2118}
2119
2120fn layout_kind_from_metadata(_node_id: NodeId, info: &RuntimeNodeMetadata) -> LayoutNodeKind {
2121 match &info.role {
2122 SemanticsRole::Layout => LayoutNodeKind::Layout,
2123 SemanticsRole::Subcompose => LayoutNodeKind::Subcompose,
2124 SemanticsRole::Text { .. } => {
2125 LayoutNodeKind::Layout
2129 }
2130 SemanticsRole::Spacer => LayoutNodeKind::Spacer,
2131 SemanticsRole::Button => {
2132 let handler = info
2133 .button_handler
2134 .as_ref()
2135 .cloned()
2136 .unwrap_or_else(|| Rc::new(RefCell::new(|| {})));
2137 LayoutNodeKind::Button { on_click: handler }
2138 }
2139 SemanticsRole::Unknown => LayoutNodeKind::Unknown,
2140 }
2141}
2142
2143fn subtract_padding(constraints: Constraints, padding: EdgeInsets) -> Constraints {
2144 let horizontal = padding.horizontal_sum();
2145 let vertical = padding.vertical_sum();
2146 let min_width = (constraints.min_width - horizontal).max(0.0);
2147 let mut max_width = constraints.max_width;
2148 if max_width.is_finite() {
2149 max_width = (max_width - horizontal).max(0.0);
2150 }
2151 let min_height = (constraints.min_height - vertical).max(0.0);
2152 let mut max_height = constraints.max_height;
2153 if max_height.is_finite() {
2154 max_height = (max_height - vertical).max(0.0);
2155 }
2156 normalize_constraints(Constraints {
2157 min_width,
2158 max_width,
2159 min_height,
2160 max_height,
2161 })
2162}
2163
2164#[cfg(test)]
2165pub(crate) fn align_horizontal(alignment: HorizontalAlignment, available: f32, child: f32) -> f32 {
2166 match alignment {
2167 HorizontalAlignment::Start => 0.0,
2168 HorizontalAlignment::CenterHorizontally => ((available - child) / 2.0).max(0.0),
2169 HorizontalAlignment::End => (available - child).max(0.0),
2170 }
2171}
2172
2173#[cfg(test)]
2174pub(crate) fn align_vertical(alignment: VerticalAlignment, available: f32, child: f32) -> f32 {
2175 match alignment {
2176 VerticalAlignment::Top => 0.0,
2177 VerticalAlignment::CenterVertically => ((available - child) / 2.0).max(0.0),
2178 VerticalAlignment::Bottom => (available - child).max(0.0),
2179 }
2180}
2181
2182fn resolve_dimension(
2183 base: f32,
2184 explicit: DimensionConstraint,
2185 min_override: Option<f32>,
2186 max_override: Option<f32>,
2187 min_limit: f32,
2188 max_limit: f32,
2189) -> f32 {
2190 let mut min_bound = min_limit;
2191 if let Some(min_value) = min_override {
2192 min_bound = min_bound.max(min_value);
2193 }
2194
2195 let mut max_bound = if max_limit.is_finite() {
2196 max_limit
2197 } else {
2198 max_override.unwrap_or(max_limit)
2199 };
2200 if let Some(max_value) = max_override {
2201 if max_bound.is_finite() {
2202 max_bound = max_bound.min(max_value);
2203 } else {
2204 max_bound = max_value;
2205 }
2206 }
2207 if max_bound < min_bound {
2208 max_bound = min_bound;
2209 }
2210
2211 let mut size = match explicit {
2212 DimensionConstraint::Points(points) => points,
2213 DimensionConstraint::Fraction(fraction) => {
2214 if max_limit.is_finite() {
2215 max_limit * fraction.clamp(0.0, 1.0)
2216 } else {
2217 base
2218 }
2219 }
2220 DimensionConstraint::Unspecified => base,
2221 DimensionConstraint::Intrinsic(_) => base,
2224 };
2225
2226 size = clamp_dimension(size, min_bound, max_bound);
2227 size = clamp_dimension(size, min_limit, max_limit);
2228 size.max(0.0)
2229}
2230
2231fn clamp_dimension(value: f32, min: f32, max: f32) -> f32 {
2232 let mut result = value.max(min);
2233 if max.is_finite() {
2234 result = result.min(max);
2235 }
2236 result
2237}
2238
2239fn normalize_constraints(mut constraints: Constraints) -> Constraints {
2240 if constraints.max_width < constraints.min_width {
2241 constraints.max_width = constraints.min_width;
2242 }
2243 if constraints.max_height < constraints.min_height {
2244 constraints.max_height = constraints.min_height;
2245 }
2246 constraints
2247}
2248
2249#[cfg(test)]
2250#[path = "tests/layout_tests.rs"]
2251mod tests;