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 chain_constraints = Constraints {
1217 min_width: constraints.min_width,
1218 max_width: if matches!(layout_props.width(), DimensionConstraint::Unspecified) {
1219 f32::INFINITY
1220 } else {
1221 constraints.max_width
1222 },
1223 min_height: constraints.min_height,
1224 max_height: if matches!(layout_props.height(), DimensionConstraint::Unspecified) {
1225 f32::INFINITY
1226 } else {
1227 constraints.max_height
1228 },
1229 };
1230
1231 let mut modifier_chain_result = Self::measure_through_modifier_chain(
1232 &state_rc,
1233 node_id,
1234 measurables.as_slice(),
1235 &measure_policy,
1236 chain_constraints,
1237 );
1238
1239 if (chain_constraints.max_width != constraints.max_width
1240 || chain_constraints.max_height != constraints.max_height)
1241 && ((constraints.max_width.is_finite()
1242 && modifier_chain_result.result.size.width > constraints.max_width)
1243 || (constraints.max_height.is_finite()
1244 && modifier_chain_result.result.size.height > constraints.max_height))
1245 {
1246 modifier_chain_result = Self::measure_through_modifier_chain(
1247 &state_rc,
1248 node_id,
1249 measurables.as_slice(),
1250 &measure_policy,
1251 constraints,
1252 );
1253 }
1254
1255 let (width, height, policy_result, content_offset, offset) = {
1257 let result = modifier_chain_result;
1258 if let Some(err) = error.borrow_mut().take() {
1261 return Err(err);
1262 }
1263
1264 (
1265 result.result.size.width,
1266 result.result.size.height,
1267 result.result,
1268 result.content_offset,
1269 result.offset,
1270 )
1271 };
1272
1273 let mut measured_children = Vec::new();
1274 for &child_id in children.iter() {
1275 if let Some((_, record)) = records.iter().find(|(id, _)| *id == child_id) {
1276 if let Some(measured) = record.measured.borrow_mut().take() {
1277 let base_position = policy_result
1278 .placements
1279 .iter()
1280 .find(|placement| placement.node_id == child_id)
1281 .map(|placement| Point {
1282 x: placement.x,
1283 y: placement.y,
1284 })
1285 .or_else(|| record.last_position.borrow().as_ref().copied())
1286 .unwrap_or(Point { x: 0.0, y: 0.0 });
1287 let position = Point {
1289 x: content_offset.x + base_position.x,
1290 y: content_offset.y + base_position.y,
1291 };
1292 measured_children.push(MeasuredChild {
1293 node: measured,
1294 offset: position,
1295 });
1296 }
1297 }
1298 }
1299
1300 let measured = Rc::new(MeasuredNode::new(
1301 node_id,
1302 Size { width, height },
1303 offset,
1304 content_offset,
1305 measured_children,
1306 ));
1307
1308 cache.store_measurement(constraints, Rc::clone(&measured));
1309
1310 Self::with_applier_result(&state_rc, |applier| {
1312 applier.with_node::<LayoutNode, _>(node_id, |node| {
1313 node.clear_needs_measure();
1314 node.clear_needs_layout();
1315 node.set_measured_size(Size { width, height });
1316 node.set_content_offset(content_offset);
1317 })
1318 })
1319 .ok();
1320
1321 Ok(measured)
1322 }
1323}
1324
1325struct LayoutNodeSnapshot {
1332 resolved_modifiers: ResolvedModifiers,
1333 measure_policy: Rc<dyn MeasurePolicy>,
1334 children: Vec<NodeId>,
1335 cache: LayoutNodeCacheHandles,
1336 needs_measure: bool,
1338}
1339
1340impl LayoutNodeSnapshot {
1341 fn from_layout_node(node: &LayoutNode) -> Self {
1342 Self {
1343 resolved_modifiers: node.resolved_modifiers(),
1344 measure_policy: Rc::clone(&node.measure_policy),
1345 children: node.children.iter().copied().collect(),
1346 cache: node.cache_handles(),
1347 needs_measure: node.needs_measure(),
1348 }
1349 }
1350}
1351
1352struct VecPools {
1354 state: Rc<RefCell<LayoutBuilderState>>,
1355 measurables: Option<Vec<Box<dyn Measurable>>>,
1356 records: Option<Vec<(NodeId, ChildRecord)>>,
1357}
1358
1359impl VecPools {
1360 fn acquire(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1361 let measurables = {
1362 let mut state_mut = state.borrow_mut();
1363 std::mem::take(&mut state_mut.tmp_measurables)
1364 };
1365 let records = {
1366 let mut state_mut = state.borrow_mut();
1367 std::mem::take(&mut state_mut.tmp_records)
1368 };
1369 Self {
1370 state,
1371 measurables: Some(measurables),
1372 records: Some(records),
1373 }
1374 }
1375
1376 #[allow(clippy::type_complexity)] fn parts(
1378 &mut self,
1379 ) -> (
1380 &mut Vec<Box<dyn Measurable>>,
1381 &mut Vec<(NodeId, ChildRecord)>,
1382 ) {
1383 let measurables = self
1384 .measurables
1385 .as_mut()
1386 .expect("measurables already returned");
1387 let records = self.records.as_mut().expect("records already returned");
1388 (measurables, records)
1389 }
1390}
1391
1392impl Drop for VecPools {
1393 fn drop(&mut self) {
1394 let mut state = self.state.borrow_mut();
1395 if let Some(mut measurables) = self.measurables.take() {
1396 measurables.clear();
1397 state.tmp_measurables = measurables;
1398 }
1399 if let Some(mut records) = self.records.take() {
1400 records.clear();
1401 state.tmp_records = records;
1402 }
1403 }
1404}
1405
1406struct SlotsGuard {
1407 state: Rc<RefCell<LayoutBuilderState>>,
1408 slots: Option<SlotBackend>,
1409}
1410
1411impl SlotsGuard {
1412 fn take(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1413 let slots = {
1414 let state_ref = state.borrow();
1415 let mut slots_ref = state_ref.slots.borrow_mut();
1416 std::mem::take(&mut *slots_ref)
1417 };
1418 Self {
1419 state,
1420 slots: Some(slots),
1421 }
1422 }
1423
1424 fn host(&mut self) -> Rc<SlotsHost> {
1425 let slots = self.slots.take().unwrap_or_default();
1426 Rc::new(SlotsHost::new(slots))
1427 }
1428
1429 fn restore(&mut self, slots: SlotBackend) {
1430 debug_assert!(self.slots.is_none());
1431 self.slots = Some(slots);
1432 }
1433}
1434
1435impl Drop for SlotsGuard {
1436 fn drop(&mut self) {
1437 if let Some(slots) = self.slots.take() {
1438 let state_ref = self.state.borrow();
1439 *state_ref.slots.borrow_mut() = slots;
1440 }
1441 }
1442}
1443
1444#[derive(Clone)]
1445struct LayoutMeasureHandle {
1446 state: Rc<RefCell<LayoutBuilderState>>,
1447}
1448
1449impl LayoutMeasureHandle {
1450 fn new(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1451 Self { state }
1452 }
1453
1454 fn measure(
1455 &self,
1456 node_id: NodeId,
1457 constraints: Constraints,
1458 ) -> Result<Rc<MeasuredNode>, NodeError> {
1459 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
1460 }
1461}
1462
1463#[derive(Debug, Clone)]
1464pub(crate) struct MeasuredNode {
1465 node_id: NodeId,
1466 size: Size,
1467 offset: Point,
1469 content_offset: Point,
1471 children: Vec<MeasuredChild>,
1472}
1473
1474impl MeasuredNode {
1475 fn new(
1476 node_id: NodeId,
1477 size: Size,
1478 offset: Point,
1479 content_offset: Point,
1480 children: Vec<MeasuredChild>,
1481 ) -> Self {
1482 Self {
1483 node_id,
1484 size,
1485 offset,
1486 content_offset,
1487 children,
1488 }
1489 }
1490}
1491
1492#[derive(Debug, Clone)]
1493struct MeasuredChild {
1494 node: Rc<MeasuredNode>,
1495 offset: Point,
1496}
1497
1498struct ChildRecord {
1499 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1500 last_position: Rc<RefCell<Option<Point>>>,
1501}
1502
1503struct LayoutChildMeasurable {
1504 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1505 node_id: NodeId,
1506 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1507 last_position: Rc<RefCell<Option<Point>>>,
1508 error: Rc<RefCell<Option<NodeError>>>,
1509 runtime_handle: Option<RuntimeHandle>,
1510 cache: LayoutNodeCacheHandles,
1511 cache_epoch: u64,
1512 measure_handle: Option<LayoutMeasureHandle>,
1513 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1514}
1515
1516impl LayoutChildMeasurable {
1517 #[allow(clippy::too_many_arguments)] fn new(
1519 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1520 node_id: NodeId,
1521 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1522 last_position: Rc<RefCell<Option<Point>>>,
1523 error: Rc<RefCell<Option<NodeError>>>,
1524 runtime_handle: Option<RuntimeHandle>,
1525 cache: LayoutNodeCacheHandles,
1526 cache_epoch: u64,
1527 measure_handle: Option<LayoutMeasureHandle>,
1528 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1529 ) -> Self {
1530 cache.activate(cache_epoch);
1531 Self {
1532 applier,
1533 node_id,
1534 measured,
1535 last_position,
1536 error,
1537 runtime_handle,
1538 cache,
1539 cache_epoch,
1540 measure_handle,
1541 layout_state,
1542 }
1543 }
1544
1545 fn record_error(&self, err: NodeError) {
1546 let mut slot = self.error.borrow_mut();
1547 if slot.is_none() {
1548 *slot = Some(err);
1549 }
1550 }
1551
1552 fn perform_measure(&self, constraints: Constraints) -> Result<Rc<MeasuredNode>, NodeError> {
1553 if let Some(handle) = &self.measure_handle {
1554 handle.measure(self.node_id, constraints)
1555 } else {
1556 measure_node_with_host(
1557 Rc::clone(&self.applier),
1558 self.runtime_handle.clone(),
1559 self.node_id,
1560 constraints,
1561 self.cache_epoch,
1562 )
1563 }
1564 }
1565
1566 fn intrinsic_measure(&self, constraints: Constraints) -> Option<Rc<MeasuredNode>> {
1567 self.cache.activate(self.cache_epoch);
1568 if let Some(cached) = self.cache.get_measurement(constraints) {
1569 return Some(cached);
1570 }
1571
1572 match self.perform_measure(constraints) {
1573 Ok(measured) => {
1574 self.cache
1575 .store_measurement(constraints, Rc::clone(&measured));
1576 Some(measured)
1577 }
1578 Err(err) => {
1579 self.record_error(err);
1580 None
1581 }
1582 }
1583 }
1584}
1585
1586impl Measurable for LayoutChildMeasurable {
1587 fn measure(&self, constraints: Constraints) -> Box<dyn Placeable> {
1588 self.cache.activate(self.cache_epoch);
1589 let measured_size;
1590 if let Some(cached) = self.cache.get_measurement(constraints) {
1591 measured_size = cached.size;
1592 *self.measured.borrow_mut() = Some(Rc::clone(&cached));
1593 } else {
1594 match self.perform_measure(constraints) {
1595 Ok(measured) => {
1596 measured_size = measured.size;
1597 self.cache
1598 .store_measurement(constraints, Rc::clone(&measured));
1599 *self.measured.borrow_mut() = Some(measured);
1600 }
1601 Err(err) => {
1602 self.record_error(err);
1603 self.measured.borrow_mut().take();
1604 measured_size = Size {
1605 width: 0.0,
1606 height: 0.0,
1607 };
1608 }
1609 }
1610 }
1611
1612 if let Some(state) = &self.layout_state {
1615 let mut state = state.borrow_mut();
1616 state.size = measured_size;
1617 state.measurement_constraints = constraints;
1618 } else if let Ok(mut applier) = self.applier.try_borrow_typed() {
1619 let _ = applier.with_node::<LayoutNode, _>(self.node_id, |node| {
1620 node.set_measured_size(measured_size);
1621 node.set_measurement_constraints(constraints);
1622 });
1623 }
1624
1625 Box::new(LayoutChildPlaceable::new(
1626 Rc::clone(&self.applier),
1627 self.node_id,
1628 Rc::clone(&self.measured),
1629 Rc::clone(&self.last_position),
1630 self.layout_state.clone(),
1631 ))
1632 }
1633
1634 fn min_intrinsic_width(&self, height: f32) -> f32 {
1635 let kind = IntrinsicKind::MinWidth(height);
1636 self.cache.activate(self.cache_epoch);
1637 if let Some(value) = self.cache.get_intrinsic(&kind) {
1638 return value;
1639 }
1640 let constraints = Constraints {
1641 min_width: 0.0,
1642 max_width: f32::INFINITY,
1643 min_height: height,
1644 max_height: height,
1645 };
1646 if let Some(node) = self.intrinsic_measure(constraints) {
1647 let value = node.size.width;
1648 self.cache.store_intrinsic(kind, value);
1649 value
1650 } else {
1651 0.0
1652 }
1653 }
1654
1655 fn max_intrinsic_width(&self, height: f32) -> f32 {
1656 let kind = IntrinsicKind::MaxWidth(height);
1657 self.cache.activate(self.cache_epoch);
1658 if let Some(value) = self.cache.get_intrinsic(&kind) {
1659 return value;
1660 }
1661 let constraints = Constraints {
1662 min_width: 0.0,
1663 max_width: f32::INFINITY,
1664 min_height: 0.0,
1665 max_height: height,
1666 };
1667 if let Some(node) = self.intrinsic_measure(constraints) {
1668 let value = node.size.width;
1669 self.cache.store_intrinsic(kind, value);
1670 value
1671 } else {
1672 0.0
1673 }
1674 }
1675
1676 fn min_intrinsic_height(&self, width: f32) -> f32 {
1677 let kind = IntrinsicKind::MinHeight(width);
1678 self.cache.activate(self.cache_epoch);
1679 if let Some(value) = self.cache.get_intrinsic(&kind) {
1680 return value;
1681 }
1682 let constraints = Constraints {
1683 min_width: width,
1684 max_width: width,
1685 min_height: 0.0,
1686 max_height: f32::INFINITY,
1687 };
1688 if let Some(node) = self.intrinsic_measure(constraints) {
1689 let value = node.size.height;
1690 self.cache.store_intrinsic(kind, value);
1691 value
1692 } else {
1693 0.0
1694 }
1695 }
1696
1697 fn max_intrinsic_height(&self, width: f32) -> f32 {
1698 let kind = IntrinsicKind::MaxHeight(width);
1699 self.cache.activate(self.cache_epoch);
1700 if let Some(value) = self.cache.get_intrinsic(&kind) {
1701 return value;
1702 }
1703 let constraints = Constraints {
1704 min_width: 0.0,
1705 max_width: width,
1706 min_height: 0.0,
1707 max_height: f32::INFINITY,
1708 };
1709 if let Some(node) = self.intrinsic_measure(constraints) {
1710 let value = node.size.height;
1711 self.cache.store_intrinsic(kind, value);
1712 value
1713 } else {
1714 0.0
1715 }
1716 }
1717
1718 fn flex_parent_data(&self) -> Option<cranpose_ui_layout::FlexParentData> {
1719 let Ok(mut applier) = self.applier.try_borrow_typed() else {
1722 return None;
1723 };
1724
1725 applier
1726 .with_node::<LayoutNode, _>(self.node_id, |layout_node| {
1727 let props = layout_node.resolved_modifiers().layout_properties();
1728 props.weight().map(|weight_data| {
1729 cranpose_ui_layout::FlexParentData::new(weight_data.weight, weight_data.fill)
1730 })
1731 })
1732 .ok()
1733 .flatten()
1734 }
1735}
1736
1737struct LayoutChildPlaceable {
1738 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1739 node_id: NodeId,
1740 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1741 last_position: Rc<RefCell<Option<Point>>>,
1742 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1743}
1744
1745impl LayoutChildPlaceable {
1746 fn new(
1747 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1748 node_id: NodeId,
1749 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1750 last_position: Rc<RefCell<Option<Point>>>,
1751 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1752 ) -> Self {
1753 Self {
1754 applier,
1755 node_id,
1756 measured,
1757 last_position,
1758 layout_state,
1759 }
1760 }
1761}
1762
1763impl Placeable for LayoutChildPlaceable {
1764 fn place(&self, x: f32, y: f32) {
1765 let internal_offset = self
1768 .measured
1769 .borrow()
1770 .as_ref()
1771 .map(|m| m.offset)
1772 .unwrap_or_default();
1773
1774 let position = Point {
1775 x: x + internal_offset.x,
1776 y: y + internal_offset.y,
1777 };
1778 *self.last_position.borrow_mut() = Some(position);
1780
1781 if let Some(state) = &self.layout_state {
1784 let mut state = state.borrow_mut();
1785 state.position = position;
1786 state.is_placed = true;
1787 } else if let Ok(mut applier) = self.applier.try_borrow_typed() {
1788 if applier
1790 .with_node::<LayoutNode, _>(self.node_id, |node| {
1791 node.set_position(position);
1792 })
1793 .is_err()
1794 {
1795 let _ = applier.with_node::<SubcomposeLayoutNode, _>(self.node_id, |node| {
1796 node.set_position(position);
1797 });
1798 }
1799 }
1800 }
1801
1802 fn width(&self) -> f32 {
1803 self.measured
1804 .borrow()
1805 .as_ref()
1806 .map(|node| node.size.width)
1807 .unwrap_or(0.0)
1808 }
1809
1810 fn height(&self) -> f32 {
1811 self.measured
1812 .borrow()
1813 .as_ref()
1814 .map(|node| node.size.height)
1815 .unwrap_or(0.0)
1816 }
1817
1818 fn node_id(&self) -> NodeId {
1819 self.node_id
1820 }
1821}
1822
1823fn measure_node_with_host(
1824 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1825 runtime_handle: Option<RuntimeHandle>,
1826 node_id: NodeId,
1827 constraints: Constraints,
1828 epoch: u64,
1829) -> Result<Rc<MeasuredNode>, NodeError> {
1830 let runtime_handle = match runtime_handle {
1831 Some(handle) => Some(handle),
1832 None => applier.borrow_typed().runtime_handle(),
1833 };
1834 let mut builder = LayoutBuilder::new_with_epoch(
1835 applier,
1836 epoch,
1837 Rc::new(RefCell::new(SlotBackend::default())),
1838 );
1839 builder.set_runtime_handle(runtime_handle);
1840 builder.measure_node(node_id, constraints)
1841}
1842
1843#[derive(Clone)]
1844struct RuntimeNodeMetadata {
1845 modifier: Modifier,
1846 resolved_modifiers: ResolvedModifiers,
1847 modifier_slices: Rc<ModifierNodeSlices>,
1848 role: SemanticsRole,
1849 button_handler: Option<Rc<RefCell<dyn FnMut()>>>,
1850}
1851
1852impl Default for RuntimeNodeMetadata {
1853 fn default() -> Self {
1854 Self {
1855 modifier: Modifier::empty(),
1856 resolved_modifiers: ResolvedModifiers::default(),
1857 modifier_slices: Rc::default(),
1858 role: SemanticsRole::Unknown,
1859 button_handler: None,
1860 }
1861 }
1862}
1863
1864fn collect_runtime_metadata(
1865 applier: &mut MemoryApplier,
1866 node: &MeasuredNode,
1867) -> Result<HashMap<NodeId, RuntimeNodeMetadata>, NodeError> {
1868 let mut map = HashMap::default();
1869 collect_runtime_metadata_inner(applier, node, &mut map)?;
1870 Ok(map)
1871}
1872
1873fn collect_semantics_with_owner(
1875 applier: &mut MemoryApplier,
1876 node: &MeasuredNode,
1877 owner: &SemanticsOwner,
1878) -> Result<(), NodeError> {
1879 owner.get_or_compute(node.node_id, applier);
1881
1882 for child in &node.children {
1884 collect_semantics_with_owner(applier, &child.node, owner)?;
1885 }
1886 Ok(())
1887}
1888
1889fn collect_semantics_snapshot(
1890 applier: &mut MemoryApplier,
1891 node: &MeasuredNode,
1892) -> Result<HashMap<NodeId, Option<SemanticsConfiguration>>, NodeError> {
1893 let owner = SemanticsOwner::new();
1894 collect_semantics_with_owner(applier, node, &owner)?;
1895
1896 let mut map = HashMap::default();
1898 extract_configurations_recursive(node, &owner, &mut map);
1899 Ok(map)
1900}
1901
1902fn extract_configurations_recursive(
1903 node: &MeasuredNode,
1904 owner: &SemanticsOwner,
1905 map: &mut HashMap<NodeId, Option<SemanticsConfiguration>>,
1906) {
1907 if let Some(config) = owner.configurations.borrow().get(&node.node_id) {
1908 map.insert(node.node_id, config.clone());
1909 }
1910 for child in &node.children {
1911 extract_configurations_recursive(&child.node, owner, map);
1912 }
1913}
1914
1915fn collect_runtime_metadata_inner(
1916 applier: &mut MemoryApplier,
1917 node: &MeasuredNode,
1918 map: &mut HashMap<NodeId, RuntimeNodeMetadata>,
1919) -> Result<(), NodeError> {
1920 if let Entry::Vacant(entry) = map.entry(node.node_id) {
1921 let meta = runtime_metadata_for(applier, node.node_id)?;
1922 entry.insert(meta);
1923 }
1924 for child in &node.children {
1925 collect_runtime_metadata_inner(applier, &child.node, map)?;
1926 }
1927 Ok(())
1928}
1929
1930fn extract_text_from_layout_node(layout: &LayoutNode) -> Option<String> {
1938 layout
1941 .semantics_configuration()
1942 .and_then(|config| config.content_description)
1943}
1944
1945fn runtime_metadata_for(
1946 applier: &mut MemoryApplier,
1947 node_id: NodeId,
1948) -> Result<RuntimeNodeMetadata, NodeError> {
1949 if let Ok(meta) = applier.with_node::<LayoutNode, _>(node_id, |layout| {
1954 let role = if let Some(text) = extract_text_from_layout_node(layout) {
1956 SemanticsRole::Text { value: text }
1957 } else {
1958 SemanticsRole::Layout
1959 };
1960
1961 RuntimeNodeMetadata {
1962 modifier: layout.modifier.clone(),
1963 resolved_modifiers: layout.resolved_modifiers(),
1964 modifier_slices: layout.modifier_slices_snapshot(),
1965 role,
1966 button_handler: None,
1967 }
1968 }) {
1969 return Ok(meta);
1970 }
1971
1972 if let Ok((modifier, resolved_modifiers)) = applier
1974 .with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1975 (node.modifier(), node.resolved_modifiers())
1976 })
1977 {
1978 let modifier_slices = Rc::new(collect_slices_from_modifier(&modifier));
1981 return Ok(RuntimeNodeMetadata {
1982 modifier,
1983 resolved_modifiers,
1984 modifier_slices,
1985 role: SemanticsRole::Subcompose,
1986 button_handler: None,
1987 });
1988 }
1989 Ok(RuntimeNodeMetadata::default())
1990}
1991
1992fn compute_semantics_for_node(
1996 applier: &mut MemoryApplier,
1997 node_id: NodeId,
1998) -> Option<SemanticsConfiguration> {
1999 match applier.with_node::<LayoutNode, _>(node_id, |layout| {
2001 let config = layout.semantics_configuration();
2002 layout.clear_needs_semantics();
2003 config
2004 }) {
2005 Ok(config) => return config,
2006 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {}
2007 Err(_) => return None,
2008 }
2009
2010 if let Ok(modifier) =
2012 applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| node.modifier())
2013 {
2014 return collect_semantics_from_modifier(&modifier);
2015 }
2016
2017 None
2018}
2019
2020fn build_semantics_node(
2024 node: &MeasuredNode,
2025 metadata: &HashMap<NodeId, RuntimeNodeMetadata>,
2026 semantics: &HashMap<NodeId, Option<SemanticsConfiguration>>,
2027) -> SemanticsNode {
2028 let info = metadata.get(&node.node_id).cloned().unwrap_or_default();
2029
2030 let mut role = info.role.clone();
2032 let mut actions = Vec::new();
2033 let mut description = None;
2034
2035 if let Some(config) = semantics.get(&node.node_id).cloned().flatten() {
2037 if config.is_button {
2039 role = SemanticsRole::Button;
2040 }
2041
2042 if config.is_clickable {
2044 actions.push(SemanticsAction::Click {
2045 handler: SemanticsCallback::new(node.node_id),
2046 });
2047 }
2048
2049 if let Some(desc) = config.content_description {
2051 description = Some(desc);
2052 }
2053 }
2054
2055 let children = node
2056 .children
2057 .iter()
2058 .map(|child| build_semantics_node(&child.node, metadata, semantics))
2059 .collect();
2060
2061 SemanticsNode::new(node.node_id, role, actions, children, description)
2062}
2063
2064fn build_layout_tree_from_metadata(
2065 node: &MeasuredNode,
2066 metadata: &HashMap<NodeId, RuntimeNodeMetadata>,
2067) -> LayoutTree {
2068 fn place(
2069 node: &MeasuredNode,
2070 origin: Point,
2071 metadata: &HashMap<NodeId, RuntimeNodeMetadata>,
2072 ) -> LayoutBox {
2073 let top_left = Point {
2075 x: origin.x + node.offset.x,
2076 y: origin.y + node.offset.y,
2077 };
2078 let rect = GeometryRect {
2079 x: top_left.x,
2080 y: top_left.y,
2081 width: node.size.width,
2082 height: node.size.height,
2083 };
2084 let info = metadata.get(&node.node_id).cloned().unwrap_or_default();
2085 let kind = layout_kind_from_metadata(node.node_id, &info);
2086 let data = LayoutNodeData::new(
2087 info.modifier.clone(),
2088 info.resolved_modifiers,
2089 info.modifier_slices.clone(),
2090 kind,
2091 );
2092 let children = node
2093 .children
2094 .iter()
2095 .map(|child| {
2096 let child_origin = Point {
2097 x: top_left.x + child.offset.x,
2098 y: top_left.y + child.offset.y,
2099 };
2100 place(&child.node, child_origin, metadata)
2101 })
2102 .collect();
2103 LayoutBox::new(node.node_id, rect, node.content_offset, data, children)
2104 }
2105
2106 LayoutTree::new(place(node, Point { x: 0.0, y: 0.0 }, metadata))
2107}
2108
2109fn layout_kind_from_metadata(_node_id: NodeId, info: &RuntimeNodeMetadata) -> LayoutNodeKind {
2110 match &info.role {
2111 SemanticsRole::Layout => LayoutNodeKind::Layout,
2112 SemanticsRole::Subcompose => LayoutNodeKind::Subcompose,
2113 SemanticsRole::Text { .. } => {
2114 LayoutNodeKind::Layout
2118 }
2119 SemanticsRole::Spacer => LayoutNodeKind::Spacer,
2120 SemanticsRole::Button => {
2121 let handler = info
2122 .button_handler
2123 .as_ref()
2124 .cloned()
2125 .unwrap_or_else(|| Rc::new(RefCell::new(|| {})));
2126 LayoutNodeKind::Button { on_click: handler }
2127 }
2128 SemanticsRole::Unknown => LayoutNodeKind::Unknown,
2129 }
2130}
2131
2132fn subtract_padding(constraints: Constraints, padding: EdgeInsets) -> Constraints {
2133 let horizontal = padding.horizontal_sum();
2134 let vertical = padding.vertical_sum();
2135 let min_width = (constraints.min_width - horizontal).max(0.0);
2136 let mut max_width = constraints.max_width;
2137 if max_width.is_finite() {
2138 max_width = (max_width - horizontal).max(0.0);
2139 }
2140 let min_height = (constraints.min_height - vertical).max(0.0);
2141 let mut max_height = constraints.max_height;
2142 if max_height.is_finite() {
2143 max_height = (max_height - vertical).max(0.0);
2144 }
2145 normalize_constraints(Constraints {
2146 min_width,
2147 max_width,
2148 min_height,
2149 max_height,
2150 })
2151}
2152
2153#[cfg(test)]
2154pub(crate) fn align_horizontal(alignment: HorizontalAlignment, available: f32, child: f32) -> f32 {
2155 match alignment {
2156 HorizontalAlignment::Start => 0.0,
2157 HorizontalAlignment::CenterHorizontally => ((available - child) / 2.0).max(0.0),
2158 HorizontalAlignment::End => (available - child).max(0.0),
2159 }
2160}
2161
2162#[cfg(test)]
2163pub(crate) fn align_vertical(alignment: VerticalAlignment, available: f32, child: f32) -> f32 {
2164 match alignment {
2165 VerticalAlignment::Top => 0.0,
2166 VerticalAlignment::CenterVertically => ((available - child) / 2.0).max(0.0),
2167 VerticalAlignment::Bottom => (available - child).max(0.0),
2168 }
2169}
2170
2171fn resolve_dimension(
2172 base: f32,
2173 explicit: DimensionConstraint,
2174 min_override: Option<f32>,
2175 max_override: Option<f32>,
2176 min_limit: f32,
2177 max_limit: f32,
2178) -> f32 {
2179 let mut min_bound = min_limit;
2180 if let Some(min_value) = min_override {
2181 min_bound = min_bound.max(min_value);
2182 }
2183
2184 let mut max_bound = if max_limit.is_finite() {
2185 max_limit
2186 } else {
2187 max_override.unwrap_or(max_limit)
2188 };
2189 if let Some(max_value) = max_override {
2190 if max_bound.is_finite() {
2191 max_bound = max_bound.min(max_value);
2192 } else {
2193 max_bound = max_value;
2194 }
2195 }
2196 if max_bound < min_bound {
2197 max_bound = min_bound;
2198 }
2199
2200 let mut size = match explicit {
2201 DimensionConstraint::Points(points) => points,
2202 DimensionConstraint::Fraction(fraction) => {
2203 if max_limit.is_finite() {
2204 max_limit * fraction.clamp(0.0, 1.0)
2205 } else {
2206 base
2207 }
2208 }
2209 DimensionConstraint::Unspecified => base,
2210 DimensionConstraint::Intrinsic(_) => base,
2213 };
2214
2215 size = clamp_dimension(size, min_bound, max_bound);
2216 size = clamp_dimension(size, min_limit, max_limit);
2217 size.max(0.0)
2218}
2219
2220fn clamp_dimension(value: f32, min: f32, max: f32) -> f32 {
2221 let mut result = value.max(min);
2222 if max.is_finite() {
2223 result = result.min(max);
2224 }
2225 result
2226}
2227
2228fn normalize_constraints(mut constraints: Constraints) -> Constraints {
2229 if constraints.max_width < constraints.min_width {
2230 constraints.max_width = constraints.min_width;
2231 }
2232 if constraints.max_height < constraints.min_height {
2233 constraints.max_height = constraints.min_height;
2234 }
2235 constraints
2236}
2237
2238#[cfg(test)]
2239#[path = "tests/layout_tests.rs"]
2240mod tests;