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: ModifierNodeSlices,
369 pub kind: LayoutNodeKind,
370}
371
372impl LayoutNodeData {
373 pub fn new(
374 modifier: Modifier,
375 resolved_modifiers: ResolvedModifiers,
376 modifier_slices: 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 let metadata = {
573 let mut applier_ref = applier_host.borrow_typed();
574 collect_runtime_metadata(&mut applier_ref, &measured)?
575 };
576
577 let semantics_snapshot = {
579 let mut applier_ref = applier_host.borrow_typed();
580 collect_semantics_snapshot(&mut applier_ref, &measured)?
581 };
582
583 drop(builder);
586
587 let semantics_root = build_semantics_node(&measured, &metadata, &semantics_snapshot);
592 let semantics = SemanticsTree::new(semantics_root);
593 let layout_tree = build_layout_tree_from_metadata(&measured, &metadata);
594
595 Ok(LayoutMeasurements::new(measured, semantics, layout_tree))
596}
597
598struct LayoutBuilder {
599 state: Rc<RefCell<LayoutBuilderState>>,
600}
601
602impl LayoutBuilder {
603 fn new_with_epoch(
604 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
605 epoch: u64,
606 slots: Rc<RefCell<SlotBackend>>,
607 ) -> Self {
608 Self {
609 state: Rc::new(RefCell::new(LayoutBuilderState::new_with_epoch(
610 applier, epoch, slots,
611 ))),
612 }
613 }
614
615 fn measure_node(
616 &mut self,
617 node_id: NodeId,
618 constraints: Constraints,
619 ) -> Result<Rc<MeasuredNode>, NodeError> {
620 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
621 }
622
623 fn set_runtime_handle(&mut self, handle: Option<RuntimeHandle>) {
624 self.state.borrow_mut().runtime_handle = handle;
625 }
626}
627
628struct LayoutBuilderState {
629 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
630 runtime_handle: Option<RuntimeHandle>,
631 slots: Rc<RefCell<SlotBackend>>,
634 cache_epoch: u64,
635 tmp_measurables: Vec<Box<dyn Measurable>>,
636 tmp_records: Vec<(NodeId, ChildRecord)>,
637}
638
639impl LayoutBuilderState {
640 fn new_with_epoch(
641 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
642 epoch: u64,
643 slots: Rc<RefCell<SlotBackend>>,
644 ) -> Self {
645 let runtime_handle = applier.borrow_typed().runtime_handle();
646
647 Self {
648 applier,
649 runtime_handle,
650 slots,
651 cache_epoch: epoch,
652 tmp_measurables: Vec::new(),
653 tmp_records: Vec::new(),
654 }
655 }
656
657 fn try_with_applier_result<R>(
658 state_rc: &Rc<RefCell<Self>>,
659 f: impl FnOnce(&mut MemoryApplier) -> Result<R, NodeError>,
660 ) -> Option<Result<R, NodeError>> {
661 let host = {
662 let state = state_rc.borrow();
663 Rc::clone(&state.applier)
664 };
665
666 let Ok(mut applier) = host.try_borrow_typed() else {
668 return None;
669 };
670
671 Some(f(&mut applier))
672 }
673
674 fn with_applier_result<R>(
675 state_rc: &Rc<RefCell<Self>>,
676 f: impl FnOnce(&mut MemoryApplier) -> Result<R, NodeError>,
677 ) -> Result<R, NodeError> {
678 Self::try_with_applier_result(state_rc, f).unwrap_or_else(|| {
679 Err(NodeError::MissingContext {
680 id: NodeId::default(),
681 reason: "applier already borrowed",
682 })
683 })
684 }
685
686 fn measure_node(
687 state_rc: Rc<RefCell<Self>>,
688 node_id: NodeId,
689 constraints: Constraints,
690 ) -> Result<Rc<MeasuredNode>, NodeError> {
691 let constraints = normalize_constraints(constraints);
692
693 if let Some(subcompose) =
695 Self::try_measure_subcompose(Rc::clone(&state_rc), node_id, constraints)?
696 {
697 return Ok(subcompose);
698 }
699
700 if let Some(result) = Self::try_with_applier_result(&state_rc, |applier| {
702 match applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
703 LayoutNodeSnapshot::from_layout_node(layout_node)
704 }) {
705 Ok(snapshot) => Ok(Some(snapshot)),
706 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => Ok(None),
707 Err(err) => Err(err),
708 }
709 }) {
710 if let Some(snapshot) = result? {
712 return Self::measure_layout_node(
713 Rc::clone(&state_rc),
714 node_id,
715 snapshot,
716 constraints,
717 );
718 }
719 }
720 Ok(Rc::new(MeasuredNode::new(
725 node_id,
726 Size::default(),
727 Point { x: 0.0, y: 0.0 },
728 Point::default(), Vec::new(),
730 )))
731 }
732
733 fn try_measure_subcompose(
734 state_rc: Rc<RefCell<Self>>,
735 node_id: NodeId,
736 constraints: Constraints,
737 ) -> Result<Option<Rc<MeasuredNode>>, NodeError> {
738 let applier_host = {
739 let state = state_rc.borrow();
740 Rc::clone(&state.applier)
741 };
742
743 let (node_handle, resolved_modifiers) = {
744 let Ok(mut applier) = applier_host.try_borrow_typed() else {
746 return Ok(None);
747 };
748 let node = match applier.get_mut(node_id) {
749 Ok(node) => node,
750 Err(NodeError::Missing { .. }) => return Ok(None),
751 Err(err) => return Err(err),
752 };
753 let any = node.as_any_mut();
754 if let Some(subcompose) = any.downcast_mut::<SubcomposeLayoutNode>() {
755 let handle = subcompose.handle();
756 let resolved_modifiers = handle.resolved_modifiers();
757 (handle, resolved_modifiers)
758 } else {
759 return Ok(None);
760 }
761 };
762
763 let runtime_handle = {
764 let mut state = state_rc.borrow_mut();
765 if state.runtime_handle.is_none() {
766 if let Ok(applier) = applier_host.try_borrow_typed() {
768 state.runtime_handle = applier.runtime_handle();
769 }
770 }
771 state
772 .runtime_handle
773 .clone()
774 .ok_or(NodeError::MissingContext {
775 id: node_id,
776 reason: "runtime handle required for subcomposition",
777 })?
778 };
779
780 let props = resolved_modifiers.layout_properties();
781 let padding = resolved_modifiers.padding();
782 let offset = resolved_modifiers.offset();
783 let mut inner_constraints = normalize_constraints(subtract_padding(constraints, padding));
784
785 if let DimensionConstraint::Points(width) = props.width() {
786 let constrained_width = width - padding.horizontal_sum();
787 inner_constraints.max_width = inner_constraints.max_width.min(constrained_width);
788 inner_constraints.min_width = inner_constraints.min_width.min(constrained_width);
789 }
790 if let DimensionConstraint::Points(height) = props.height() {
791 let constrained_height = height - padding.vertical_sum();
792 inner_constraints.max_height = inner_constraints.max_height.min(constrained_height);
793 inner_constraints.min_height = inner_constraints.min_height.min(constrained_height);
794 }
795
796 let mut slots_guard = SlotsGuard::take(Rc::clone(&state_rc));
797 let slots_host = slots_guard.host();
798 let applier_host_dyn: Rc<dyn ApplierHost> = applier_host.clone();
799 let observer = SnapshotStateObserver::new(|callback| callback());
800 let composer = Composer::new(
801 Rc::clone(&slots_host),
802 applier_host_dyn,
803 runtime_handle.clone(),
804 observer,
805 Some(node_id),
806 );
807 composer.enter_phase(Phase::Measure);
808
809 let state_rc_clone = Rc::clone(&state_rc);
810 let measure_error: Rc<RefCell<Option<NodeError>>> = Rc::new(RefCell::new(None));
811 let error_for_measurer = Rc::clone(&measure_error);
812 let measurer = Box::new(
813 move |child_id: NodeId, child_constraints: Constraints| -> Size {
814 match Self::measure_node(Rc::clone(&state_rc_clone), child_id, child_constraints) {
815 Ok(measured) => measured.size,
816 Err(err) => {
817 let mut slot = error_for_measurer.borrow_mut();
818 if slot.is_none() {
819 *slot = Some(err);
820 }
821 Size::default()
822 }
823 }
824 },
825 );
826
827 let measure_result = node_handle.measure(
828 &composer,
829 node_id,
830 inner_constraints,
831 measurer,
832 Rc::clone(&measure_error),
833 )?;
834
835 slots_guard.restore(slots_host.take());
836
837 if let Some(err) = measure_error.borrow_mut().take() {
838 return Err(err);
839 }
840
841 let mut width = measure_result.size.width + padding.horizontal_sum();
845 let mut height = measure_result.size.height + padding.vertical_sum();
846
847 width = resolve_dimension(
848 width,
849 props.width(),
850 props.min_width(),
851 props.max_width(),
852 constraints.min_width,
853 constraints.max_width,
854 );
855 height = resolve_dimension(
856 height,
857 props.height(),
858 props.min_height(),
859 props.max_height(),
860 constraints.min_height,
861 constraints.max_height,
862 );
863
864 let mut children = Vec::new();
865 for placement in measure_result.placements {
866 let child =
867 Self::measure_node(Rc::clone(&state_rc), placement.node_id, inner_constraints)?;
868 let position = Point {
869 x: padding.left + placement.x,
870 y: padding.top + placement.y,
871 };
872 children.push(MeasuredChild {
873 node: child,
874 offset: position,
875 });
876 }
877
878 Ok(Some(Rc::new(MeasuredNode::new(
879 node_id,
880 Size { width, height },
881 offset,
882 Point::default(), children,
884 ))))
885 }
886
887 fn measure_through_modifier_chain(
894 state_rc: &Rc<RefCell<Self>>,
895 node_id: NodeId,
896 measurables: &[Box<dyn Measurable>],
897 measure_policy: &Rc<dyn MeasurePolicy>,
898 constraints: Constraints,
899 ) -> ModifierChainMeasurement {
900 use cranpose_foundation::NodeCapabilities;
901
902 #[allow(clippy::type_complexity)]
904 let mut layout_node_data: Vec<(
906 usize,
907 Rc<RefCell<Box<dyn cranpose_foundation::ModifierNode>>>,
908 )> = Vec::new();
909 let mut offset = Point::default();
910
911 {
912 let state = state_rc.borrow();
913 let mut applier = state.applier.borrow_typed();
914
915 let _ = applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
916 let chain_handle = layout_node.modifier_chain();
917
918 if !chain_handle.has_layout_nodes() {
919 return;
920 }
921
922 chain_handle.chain().for_each_forward_matching(
924 NodeCapabilities::LAYOUT,
925 |node_ref| {
926 if let Some(index) = node_ref.entry_index() {
927 if let Some(node_rc) = chain_handle.chain().get_node_rc(index) {
929 layout_node_data.push((index, Rc::clone(&node_rc)));
930 }
931
932 node_ref.with_node(|node| {
936 if let Some(offset_node) =
937 node.as_any()
938 .downcast_ref::<crate::modifier_nodes::OffsetNode>()
939 {
940 let delta = offset_node.offset();
941 offset.x += delta.x;
942 offset.y += delta.y;
943 }
944 });
945 }
946 },
947 );
948 });
949 }
950
951 layout_node_data.reverse();
958
959 let shared_context = Rc::new(RefCell::new(LayoutNodeContext::new()));
961
962 let policy_result = Rc::new(RefCell::new(None));
964 let inner_coordinator: Box<dyn NodeCoordinator + '_> =
965 Box::new(coordinator::InnerCoordinator::new(
966 Rc::clone(measure_policy),
967 measurables,
968 Rc::clone(&policy_result),
969 ));
970
971 let mut current_coordinator = inner_coordinator;
973 for (_, node_rc) in layout_node_data {
974 current_coordinator = Box::new(coordinator::LayoutModifierCoordinator::new(
975 node_rc,
976 current_coordinator,
977 Rc::clone(&shared_context),
978 ));
979 }
980
981 let placeable = current_coordinator.measure(constraints);
983 let final_size = Size {
984 width: placeable.width(),
985 height: placeable.height(),
986 };
987
988 let content_offset = placeable.content_offset();
990 let all_placement_offset = Point {
991 x: content_offset.0,
992 y: content_offset.1,
993 };
994
995 let content_offset = Point {
999 x: all_placement_offset.x - offset.x,
1000 y: all_placement_offset.y - offset.y,
1001 };
1002
1003 let placements = policy_result
1006 .borrow_mut()
1007 .take()
1008 .map(|result| result.placements)
1009 .unwrap_or_default();
1010
1011 let invalidations = shared_context.borrow_mut().take_invalidations();
1013 if !invalidations.is_empty() {
1014 Self::with_applier_result(state_rc, |applier| {
1016 applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1017 for kind in invalidations {
1018 match kind {
1019 InvalidationKind::Layout => layout_node.mark_needs_measure(),
1020 InvalidationKind::Draw => layout_node.mark_needs_redraw(),
1021 InvalidationKind::Semantics => layout_node.mark_needs_semantics(),
1022 InvalidationKind::PointerInput => layout_node.mark_needs_pointer_pass(),
1023 InvalidationKind::Focus => layout_node.mark_needs_focus_sync(),
1024 }
1025 }
1026 })
1027 })
1028 .ok();
1029 }
1030
1031 ModifierChainMeasurement {
1032 result: MeasureResult {
1033 size: final_size,
1034 placements,
1035 },
1036 content_offset,
1037 offset,
1038 }
1039 }
1040
1041 fn measure_layout_node(
1042 state_rc: Rc<RefCell<Self>>,
1043 node_id: NodeId,
1044 snapshot: LayoutNodeSnapshot,
1045 constraints: Constraints,
1046 ) -> Result<Rc<MeasuredNode>, NodeError> {
1047 let cache_epoch = {
1048 let state = state_rc.borrow();
1049 state.cache_epoch
1050 };
1051 let LayoutNodeSnapshot {
1052 resolved_modifiers,
1053 measure_policy,
1054 children,
1055 cache,
1056 needs_measure,
1057 } = snapshot;
1058 cache.activate(cache_epoch);
1059 let layout_props = resolved_modifiers.layout_properties();
1060
1061 if needs_measure {
1062 }
1064
1065 if !needs_measure {
1069 if let Some(cached) = cache.get_measurement(constraints) {
1071 Self::with_applier_result(&state_rc, |applier| {
1073 applier.with_node::<LayoutNode, _>(node_id, |node| {
1074 node.clear_needs_measure();
1075 node.clear_needs_layout();
1076 })
1077 })
1078 .ok();
1079 return Ok(cached);
1080 }
1081 }
1082
1083 let (runtime_handle, applier_host) = {
1084 let state = state_rc.borrow();
1085 (state.runtime_handle.clone(), Rc::clone(&state.applier))
1086 };
1087
1088 let measure_handle = LayoutMeasureHandle::new(Rc::clone(&state_rc));
1089 let error = Rc::new(RefCell::new(None));
1090 let mut pools = VecPools::acquire(Rc::clone(&state_rc));
1091 let (measurables, records) = pools.parts();
1092
1093 for &child_id in children.iter() {
1094 let measured = Rc::new(RefCell::new(None));
1095 let position = Rc::new(RefCell::new(None));
1096 let cache_handles = {
1097 let mut applier = applier_host.borrow_typed();
1098 match applier
1099 .with_node::<LayoutNode, _>(child_id, |layout_node| layout_node.cache_handles())
1100 {
1101 Ok(value) => Some(value),
1102 Err(NodeError::TypeMismatch { .. }) => Some(LayoutNodeCacheHandles::default()),
1103 Err(NodeError::Missing { .. }) => None,
1104 Err(err) => return Err(err),
1105 }
1106 };
1107 let Some(cache_handles) = cache_handles else {
1108 continue;
1109 };
1110 cache_handles.activate(cache_epoch);
1111
1112 records.push((
1113 child_id,
1114 ChildRecord {
1115 measured: Rc::clone(&measured),
1116 last_position: Rc::clone(&position),
1117 },
1118 ));
1119 measurables.push(Box::new(LayoutChildMeasurable::new(
1120 Rc::clone(&applier_host),
1121 child_id,
1122 measured,
1123 position,
1124 Rc::clone(&error),
1125 runtime_handle.clone(),
1126 cache_handles,
1127 cache_epoch,
1128 Some(measure_handle.clone()),
1129 )));
1130 }
1131
1132 let chain_constraints = Constraints {
1134 min_width: constraints.min_width,
1135 max_width: if matches!(layout_props.width(), DimensionConstraint::Unspecified) {
1136 f32::INFINITY
1137 } else {
1138 constraints.max_width
1139 },
1140 min_height: constraints.min_height,
1141 max_height: if matches!(layout_props.height(), DimensionConstraint::Unspecified) {
1142 f32::INFINITY
1143 } else {
1144 constraints.max_height
1145 },
1146 };
1147
1148 let mut modifier_chain_result = Self::measure_through_modifier_chain(
1149 &state_rc,
1150 node_id,
1151 measurables.as_slice(),
1152 &measure_policy,
1153 chain_constraints,
1154 );
1155
1156 if (chain_constraints.max_width != constraints.max_width
1157 || chain_constraints.max_height != constraints.max_height)
1158 && ((constraints.max_width.is_finite()
1159 && modifier_chain_result.result.size.width > constraints.max_width)
1160 || (constraints.max_height.is_finite()
1161 && modifier_chain_result.result.size.height > constraints.max_height))
1162 {
1163 modifier_chain_result = Self::measure_through_modifier_chain(
1164 &state_rc,
1165 node_id,
1166 measurables.as_slice(),
1167 &measure_policy,
1168 constraints,
1169 );
1170 }
1171
1172 let (width, height, policy_result, content_offset, offset) = {
1174 let result = modifier_chain_result;
1175 if let Some(err) = error.borrow_mut().take() {
1178 return Err(err);
1179 }
1180
1181 (
1182 result.result.size.width,
1183 result.result.size.height,
1184 result.result,
1185 result.content_offset,
1186 result.offset,
1187 )
1188 };
1189
1190 let mut measured_children = Vec::new();
1191 for &child_id in children.iter() {
1192 if let Some((_, record)) = records.iter().find(|(id, _)| *id == child_id) {
1193 if let Some(measured) = record.measured.borrow_mut().take() {
1194 let base_position = policy_result
1195 .placements
1196 .iter()
1197 .find(|placement| placement.node_id == child_id)
1198 .map(|placement| Point {
1199 x: placement.x,
1200 y: placement.y,
1201 })
1202 .or_else(|| record.last_position.borrow().as_ref().copied())
1203 .unwrap_or(Point { x: 0.0, y: 0.0 });
1204 let position = Point {
1206 x: content_offset.x + base_position.x,
1207 y: content_offset.y + base_position.y,
1208 };
1209 measured_children.push(MeasuredChild {
1210 node: measured,
1211 offset: position,
1212 });
1213 }
1214 }
1215 }
1216
1217 let measured = Rc::new(MeasuredNode::new(
1218 node_id,
1219 Size { width, height },
1220 offset,
1221 content_offset,
1222 measured_children,
1223 ));
1224
1225 cache.store_measurement(constraints, Rc::clone(&measured));
1226
1227 Self::with_applier_result(&state_rc, |applier| {
1229 applier.with_node::<LayoutNode, _>(node_id, |node| {
1230 node.clear_needs_measure();
1231 node.clear_needs_layout();
1232 })
1233 })
1234 .ok();
1235
1236 Ok(measured)
1237 }
1238}
1239
1240struct LayoutNodeSnapshot {
1247 resolved_modifiers: ResolvedModifiers,
1248 measure_policy: Rc<dyn MeasurePolicy>,
1249 children: Vec<NodeId>,
1250 cache: LayoutNodeCacheHandles,
1251 needs_measure: bool,
1253}
1254
1255impl LayoutNodeSnapshot {
1256 fn from_layout_node(node: &LayoutNode) -> Self {
1257 Self {
1258 resolved_modifiers: node.resolved_modifiers(),
1259 measure_policy: Rc::clone(&node.measure_policy),
1260 children: node.children.iter().copied().collect(),
1261 cache: node.cache_handles(),
1262 needs_measure: node.needs_measure(),
1263 }
1264 }
1265}
1266
1267struct VecPools {
1269 state: Rc<RefCell<LayoutBuilderState>>,
1270 measurables: Option<Vec<Box<dyn Measurable>>>,
1271 records: Option<Vec<(NodeId, ChildRecord)>>,
1272}
1273
1274impl VecPools {
1275 fn acquire(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1276 let measurables = {
1277 let mut state_mut = state.borrow_mut();
1278 std::mem::take(&mut state_mut.tmp_measurables)
1279 };
1280 let records = {
1281 let mut state_mut = state.borrow_mut();
1282 std::mem::take(&mut state_mut.tmp_records)
1283 };
1284 Self {
1285 state,
1286 measurables: Some(measurables),
1287 records: Some(records),
1288 }
1289 }
1290
1291 #[allow(clippy::type_complexity)] fn parts(
1293 &mut self,
1294 ) -> (
1295 &mut Vec<Box<dyn Measurable>>,
1296 &mut Vec<(NodeId, ChildRecord)>,
1297 ) {
1298 let measurables = self
1299 .measurables
1300 .as_mut()
1301 .expect("measurables already returned");
1302 let records = self.records.as_mut().expect("records already returned");
1303 (measurables, records)
1304 }
1305}
1306
1307impl Drop for VecPools {
1308 fn drop(&mut self) {
1309 let mut state = self.state.borrow_mut();
1310 if let Some(mut measurables) = self.measurables.take() {
1311 measurables.clear();
1312 state.tmp_measurables = measurables;
1313 }
1314 if let Some(mut records) = self.records.take() {
1315 records.clear();
1316 state.tmp_records = records;
1317 }
1318 }
1319}
1320
1321struct SlotsGuard {
1322 state: Rc<RefCell<LayoutBuilderState>>,
1323 slots: Option<SlotBackend>,
1324}
1325
1326impl SlotsGuard {
1327 fn take(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1328 let slots = {
1329 let state_ref = state.borrow();
1330 let mut slots_ref = state_ref.slots.borrow_mut();
1331 std::mem::take(&mut *slots_ref)
1332 };
1333 Self {
1334 state,
1335 slots: Some(slots),
1336 }
1337 }
1338
1339 fn host(&mut self) -> Rc<SlotsHost> {
1340 let slots = self.slots.take().unwrap_or_default();
1341 Rc::new(SlotsHost::new(slots))
1342 }
1343
1344 fn restore(&mut self, slots: SlotBackend) {
1345 debug_assert!(self.slots.is_none());
1346 self.slots = Some(slots);
1347 }
1348}
1349
1350impl Drop for SlotsGuard {
1351 fn drop(&mut self) {
1352 if let Some(slots) = self.slots.take() {
1353 let state_ref = self.state.borrow();
1354 *state_ref.slots.borrow_mut() = slots;
1355 }
1356 }
1357}
1358
1359#[derive(Clone)]
1360struct LayoutMeasureHandle {
1361 state: Rc<RefCell<LayoutBuilderState>>,
1362}
1363
1364impl LayoutMeasureHandle {
1365 fn new(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1366 Self { state }
1367 }
1368
1369 fn measure(
1370 &self,
1371 node_id: NodeId,
1372 constraints: Constraints,
1373 ) -> Result<Rc<MeasuredNode>, NodeError> {
1374 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
1375 }
1376}
1377
1378#[derive(Debug, Clone)]
1379pub(crate) struct MeasuredNode {
1380 node_id: NodeId,
1381 size: Size,
1382 offset: Point,
1384 content_offset: Point,
1386 children: Vec<MeasuredChild>,
1387}
1388
1389impl MeasuredNode {
1390 fn new(
1391 node_id: NodeId,
1392 size: Size,
1393 offset: Point,
1394 content_offset: Point,
1395 children: Vec<MeasuredChild>,
1396 ) -> Self {
1397 Self {
1398 node_id,
1399 size,
1400 offset,
1401 content_offset,
1402 children,
1403 }
1404 }
1405}
1406
1407#[derive(Debug, Clone)]
1408struct MeasuredChild {
1409 node: Rc<MeasuredNode>,
1410 offset: Point,
1411}
1412
1413struct ChildRecord {
1414 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1415 last_position: Rc<RefCell<Option<Point>>>,
1416}
1417
1418struct LayoutChildMeasurable {
1419 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1420 node_id: NodeId,
1421 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1422 last_position: Rc<RefCell<Option<Point>>>,
1423 error: Rc<RefCell<Option<NodeError>>>,
1424 runtime_handle: Option<RuntimeHandle>,
1425 cache: LayoutNodeCacheHandles,
1426 cache_epoch: u64,
1427 measure_handle: Option<LayoutMeasureHandle>,
1428}
1429
1430impl LayoutChildMeasurable {
1431 #[allow(clippy::too_many_arguments)] fn new(
1433 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1434 node_id: NodeId,
1435 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1436 last_position: Rc<RefCell<Option<Point>>>,
1437 error: Rc<RefCell<Option<NodeError>>>,
1438 runtime_handle: Option<RuntimeHandle>,
1439 cache: LayoutNodeCacheHandles,
1440 cache_epoch: u64,
1441 measure_handle: Option<LayoutMeasureHandle>,
1442 ) -> Self {
1443 cache.activate(cache_epoch);
1444 Self {
1445 applier,
1446 node_id,
1447 measured,
1448 last_position,
1449 error,
1450 runtime_handle,
1451 cache,
1452 cache_epoch,
1453 measure_handle,
1454 }
1455 }
1456
1457 fn record_error(&self, err: NodeError) {
1458 let mut slot = self.error.borrow_mut();
1459 if slot.is_none() {
1460 *slot = Some(err);
1461 }
1462 }
1463
1464 fn perform_measure(&self, constraints: Constraints) -> Result<Rc<MeasuredNode>, NodeError> {
1465 if let Some(handle) = &self.measure_handle {
1466 handle.measure(self.node_id, constraints)
1467 } else {
1468 measure_node_with_host(
1469 Rc::clone(&self.applier),
1470 self.runtime_handle.clone(),
1471 self.node_id,
1472 constraints,
1473 self.cache_epoch,
1474 )
1475 }
1476 }
1477
1478 fn intrinsic_measure(&self, constraints: Constraints) -> Option<Rc<MeasuredNode>> {
1479 self.cache.activate(self.cache_epoch);
1480 if let Some(cached) = self.cache.get_measurement(constraints) {
1481 return Some(cached);
1482 }
1483
1484 match self.perform_measure(constraints) {
1485 Ok(measured) => {
1486 self.cache
1487 .store_measurement(constraints, Rc::clone(&measured));
1488 Some(measured)
1489 }
1490 Err(err) => {
1491 self.record_error(err);
1492 None
1493 }
1494 }
1495 }
1496}
1497
1498impl Measurable for LayoutChildMeasurable {
1499 fn measure(&self, constraints: Constraints) -> Box<dyn Placeable> {
1500 self.cache.activate(self.cache_epoch);
1501 if let Some(cached) = self.cache.get_measurement(constraints) {
1502 *self.measured.borrow_mut() = Some(Rc::clone(&cached));
1503 } else {
1504 match self.perform_measure(constraints) {
1505 Ok(measured) => {
1506 self.cache
1507 .store_measurement(constraints, Rc::clone(&measured));
1508 *self.measured.borrow_mut() = Some(measured);
1509 }
1510 Err(err) => {
1511 self.record_error(err);
1512 self.measured.borrow_mut().take();
1513 }
1514 }
1515 }
1516 Box::new(LayoutChildPlaceable::new(
1517 self.node_id,
1518 Rc::clone(&self.measured),
1519 Rc::clone(&self.last_position),
1520 ))
1521 }
1522
1523 fn min_intrinsic_width(&self, height: f32) -> f32 {
1524 let kind = IntrinsicKind::MinWidth(height);
1525 self.cache.activate(self.cache_epoch);
1526 if let Some(value) = self.cache.get_intrinsic(&kind) {
1527 return value;
1528 }
1529 let constraints = Constraints {
1530 min_width: 0.0,
1531 max_width: f32::INFINITY,
1532 min_height: height,
1533 max_height: height,
1534 };
1535 if let Some(node) = self.intrinsic_measure(constraints) {
1536 let value = node.size.width;
1537 self.cache.store_intrinsic(kind, value);
1538 value
1539 } else {
1540 0.0
1541 }
1542 }
1543
1544 fn max_intrinsic_width(&self, height: f32) -> f32 {
1545 let kind = IntrinsicKind::MaxWidth(height);
1546 self.cache.activate(self.cache_epoch);
1547 if let Some(value) = self.cache.get_intrinsic(&kind) {
1548 return value;
1549 }
1550 let constraints = Constraints {
1551 min_width: 0.0,
1552 max_width: f32::INFINITY,
1553 min_height: 0.0,
1554 max_height: height,
1555 };
1556 if let Some(node) = self.intrinsic_measure(constraints) {
1557 let value = node.size.width;
1558 self.cache.store_intrinsic(kind, value);
1559 value
1560 } else {
1561 0.0
1562 }
1563 }
1564
1565 fn min_intrinsic_height(&self, width: f32) -> f32 {
1566 let kind = IntrinsicKind::MinHeight(width);
1567 self.cache.activate(self.cache_epoch);
1568 if let Some(value) = self.cache.get_intrinsic(&kind) {
1569 return value;
1570 }
1571 let constraints = Constraints {
1572 min_width: width,
1573 max_width: width,
1574 min_height: 0.0,
1575 max_height: f32::INFINITY,
1576 };
1577 if let Some(node) = self.intrinsic_measure(constraints) {
1578 let value = node.size.height;
1579 self.cache.store_intrinsic(kind, value);
1580 value
1581 } else {
1582 0.0
1583 }
1584 }
1585
1586 fn max_intrinsic_height(&self, width: f32) -> f32 {
1587 let kind = IntrinsicKind::MaxHeight(width);
1588 self.cache.activate(self.cache_epoch);
1589 if let Some(value) = self.cache.get_intrinsic(&kind) {
1590 return value;
1591 }
1592 let constraints = Constraints {
1593 min_width: 0.0,
1594 max_width: width,
1595 min_height: 0.0,
1596 max_height: f32::INFINITY,
1597 };
1598 if let Some(node) = self.intrinsic_measure(constraints) {
1599 let value = node.size.height;
1600 self.cache.store_intrinsic(kind, value);
1601 value
1602 } else {
1603 0.0
1604 }
1605 }
1606
1607 fn flex_parent_data(&self) -> Option<cranpose_ui_layout::FlexParentData> {
1608 let Ok(mut applier) = self.applier.try_borrow_typed() else {
1611 return None;
1612 };
1613
1614 applier
1615 .with_node::<LayoutNode, _>(self.node_id, |layout_node| {
1616 let props = layout_node.resolved_modifiers().layout_properties();
1617 props.weight().map(|weight_data| {
1618 cranpose_ui_layout::FlexParentData::new(weight_data.weight, weight_data.fill)
1619 })
1620 })
1621 .ok()
1622 .flatten()
1623 }
1624}
1625
1626struct LayoutChildPlaceable {
1627 node_id: NodeId,
1628 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1629 last_position: Rc<RefCell<Option<Point>>>,
1630}
1631
1632impl LayoutChildPlaceable {
1633 fn new(
1634 node_id: NodeId,
1635 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1636 last_position: Rc<RefCell<Option<Point>>>,
1637 ) -> Self {
1638 Self {
1639 node_id,
1640 measured,
1641 last_position,
1642 }
1643 }
1644}
1645
1646impl Placeable for LayoutChildPlaceable {
1647 fn place(&self, x: f32, y: f32) {
1648 *self.last_position.borrow_mut() = Some(Point { x, y });
1649 }
1650
1651 fn width(&self) -> f32 {
1652 self.measured
1653 .borrow()
1654 .as_ref()
1655 .map(|node| node.size.width)
1656 .unwrap_or(0.0)
1657 }
1658
1659 fn height(&self) -> f32 {
1660 self.measured
1661 .borrow()
1662 .as_ref()
1663 .map(|node| node.size.height)
1664 .unwrap_or(0.0)
1665 }
1666
1667 fn node_id(&self) -> NodeId {
1668 self.node_id
1669 }
1670}
1671
1672fn measure_node_with_host(
1673 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1674 runtime_handle: Option<RuntimeHandle>,
1675 node_id: NodeId,
1676 constraints: Constraints,
1677 epoch: u64,
1678) -> Result<Rc<MeasuredNode>, NodeError> {
1679 let runtime_handle = match runtime_handle {
1680 Some(handle) => Some(handle),
1681 None => applier.borrow_typed().runtime_handle(),
1682 };
1683 let mut builder = LayoutBuilder::new_with_epoch(
1684 applier,
1685 epoch,
1686 Rc::new(RefCell::new(SlotBackend::default())),
1687 );
1688 builder.set_runtime_handle(runtime_handle);
1689 builder.measure_node(node_id, constraints)
1690}
1691
1692#[derive(Clone)]
1693struct RuntimeNodeMetadata {
1694 modifier: Modifier,
1695 resolved_modifiers: ResolvedModifiers,
1696 modifier_slices: ModifierNodeSlices,
1697 role: SemanticsRole,
1698 button_handler: Option<Rc<RefCell<dyn FnMut()>>>,
1699}
1700
1701impl Default for RuntimeNodeMetadata {
1702 fn default() -> Self {
1703 Self {
1704 modifier: Modifier::empty(),
1705 resolved_modifiers: ResolvedModifiers::default(),
1706 modifier_slices: ModifierNodeSlices::default(),
1707 role: SemanticsRole::Unknown,
1708 button_handler: None,
1709 }
1710 }
1711}
1712
1713fn collect_runtime_metadata(
1714 applier: &mut MemoryApplier,
1715 node: &MeasuredNode,
1716) -> Result<HashMap<NodeId, RuntimeNodeMetadata>, NodeError> {
1717 let mut map = HashMap::default();
1718 collect_runtime_metadata_inner(applier, node, &mut map)?;
1719 Ok(map)
1720}
1721
1722fn collect_semantics_with_owner(
1724 applier: &mut MemoryApplier,
1725 node: &MeasuredNode,
1726 owner: &SemanticsOwner,
1727) -> Result<(), NodeError> {
1728 owner.get_or_compute(node.node_id, applier);
1730
1731 for child in &node.children {
1733 collect_semantics_with_owner(applier, &child.node, owner)?;
1734 }
1735 Ok(())
1736}
1737
1738fn collect_semantics_snapshot(
1739 applier: &mut MemoryApplier,
1740 node: &MeasuredNode,
1741) -> Result<HashMap<NodeId, Option<SemanticsConfiguration>>, NodeError> {
1742 let owner = SemanticsOwner::new();
1743 collect_semantics_with_owner(applier, node, &owner)?;
1744
1745 let mut map = HashMap::default();
1747 extract_configurations_recursive(node, &owner, &mut map);
1748 Ok(map)
1749}
1750
1751fn extract_configurations_recursive(
1752 node: &MeasuredNode,
1753 owner: &SemanticsOwner,
1754 map: &mut HashMap<NodeId, Option<SemanticsConfiguration>>,
1755) {
1756 if let Some(config) = owner.configurations.borrow().get(&node.node_id) {
1757 map.insert(node.node_id, config.clone());
1758 }
1759 for child in &node.children {
1760 extract_configurations_recursive(&child.node, owner, map);
1761 }
1762}
1763
1764fn collect_runtime_metadata_inner(
1765 applier: &mut MemoryApplier,
1766 node: &MeasuredNode,
1767 map: &mut HashMap<NodeId, RuntimeNodeMetadata>,
1768) -> Result<(), NodeError> {
1769 if let Entry::Vacant(entry) = map.entry(node.node_id) {
1770 let meta = runtime_metadata_for(applier, node.node_id)?;
1771 entry.insert(meta);
1772 }
1773 for child in &node.children {
1774 collect_runtime_metadata_inner(applier, &child.node, map)?;
1775 }
1776 Ok(())
1777}
1778
1779fn extract_text_from_layout_node(layout: &LayoutNode) -> Option<String> {
1787 layout
1790 .semantics_configuration()
1791 .and_then(|config| config.content_description)
1792}
1793
1794fn runtime_metadata_for(
1795 applier: &mut MemoryApplier,
1796 node_id: NodeId,
1797) -> Result<RuntimeNodeMetadata, NodeError> {
1798 if let Ok(meta) = applier.with_node::<LayoutNode, _>(node_id, |layout| {
1803 let role = if let Some(text) = extract_text_from_layout_node(layout) {
1805 SemanticsRole::Text { value: text }
1806 } else {
1807 SemanticsRole::Layout
1808 };
1809
1810 RuntimeNodeMetadata {
1811 modifier: layout.modifier.clone(),
1812 resolved_modifiers: layout.resolved_modifiers(),
1813 modifier_slices: layout.modifier_slices_snapshot(),
1814 role,
1815 button_handler: None,
1816 }
1817 }) {
1818 return Ok(meta);
1819 }
1820
1821 if let Ok((modifier, resolved_modifiers)) = applier
1823 .with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1824 (node.modifier(), node.resolved_modifiers())
1825 })
1826 {
1827 let modifier_slices = collect_slices_from_modifier(&modifier);
1828 return Ok(RuntimeNodeMetadata {
1829 modifier,
1830 resolved_modifiers,
1831 modifier_slices,
1832 role: SemanticsRole::Subcompose,
1833 button_handler: None,
1834 });
1835 }
1836 Ok(RuntimeNodeMetadata::default())
1837}
1838
1839fn compute_semantics_for_node(
1843 applier: &mut MemoryApplier,
1844 node_id: NodeId,
1845) -> Option<SemanticsConfiguration> {
1846 match applier.with_node::<LayoutNode, _>(node_id, |layout| {
1848 let config = layout.semantics_configuration();
1849 layout.clear_needs_semantics();
1850 config
1851 }) {
1852 Ok(config) => return config,
1853 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {}
1854 Err(_) => return None,
1855 }
1856
1857 if let Ok(modifier) =
1859 applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| node.modifier())
1860 {
1861 return collect_semantics_from_modifier(&modifier);
1862 }
1863
1864 None
1865}
1866
1867fn build_semantics_node(
1871 node: &MeasuredNode,
1872 metadata: &HashMap<NodeId, RuntimeNodeMetadata>,
1873 semantics: &HashMap<NodeId, Option<SemanticsConfiguration>>,
1874) -> SemanticsNode {
1875 let info = metadata.get(&node.node_id).cloned().unwrap_or_default();
1876
1877 let mut role = info.role.clone();
1879 let mut actions = Vec::new();
1880 let mut description = None;
1881
1882 if let Some(config) = semantics.get(&node.node_id).cloned().flatten() {
1884 if config.is_button {
1886 role = SemanticsRole::Button;
1887 }
1888
1889 if config.is_clickable {
1891 actions.push(SemanticsAction::Click {
1892 handler: SemanticsCallback::new(node.node_id),
1893 });
1894 }
1895
1896 if let Some(desc) = config.content_description {
1898 description = Some(desc);
1899 }
1900 }
1901
1902 let children = node
1903 .children
1904 .iter()
1905 .map(|child| build_semantics_node(&child.node, metadata, semantics))
1906 .collect();
1907
1908 SemanticsNode::new(node.node_id, role, actions, children, description)
1909}
1910
1911fn build_layout_tree_from_metadata(
1912 node: &MeasuredNode,
1913 metadata: &HashMap<NodeId, RuntimeNodeMetadata>,
1914) -> LayoutTree {
1915 fn place(
1916 node: &MeasuredNode,
1917 origin: Point,
1918 metadata: &HashMap<NodeId, RuntimeNodeMetadata>,
1919 ) -> LayoutBox {
1920 let top_left = Point {
1922 x: origin.x + node.offset.x,
1923 y: origin.y + node.offset.y,
1924 };
1925 let rect = GeometryRect {
1926 x: top_left.x,
1927 y: top_left.y,
1928 width: node.size.width,
1929 height: node.size.height,
1930 };
1931 let info = metadata.get(&node.node_id).cloned().unwrap_or_default();
1932 let kind = layout_kind_from_metadata(node.node_id, &info);
1933 let data = LayoutNodeData::new(
1934 info.modifier.clone(),
1935 info.resolved_modifiers,
1936 info.modifier_slices.clone(),
1937 kind,
1938 );
1939 let children = node
1940 .children
1941 .iter()
1942 .map(|child| {
1943 let child_origin = Point {
1944 x: top_left.x + child.offset.x,
1945 y: top_left.y + child.offset.y,
1946 };
1947 place(&child.node, child_origin, metadata)
1948 })
1949 .collect();
1950 LayoutBox::new(node.node_id, rect, node.content_offset, data, children)
1951 }
1952
1953 LayoutTree::new(place(node, Point { x: 0.0, y: 0.0 }, metadata))
1954}
1955
1956fn layout_kind_from_metadata(_node_id: NodeId, info: &RuntimeNodeMetadata) -> LayoutNodeKind {
1957 match &info.role {
1958 SemanticsRole::Layout => LayoutNodeKind::Layout,
1959 SemanticsRole::Subcompose => LayoutNodeKind::Subcompose,
1960 SemanticsRole::Text { .. } => {
1961 LayoutNodeKind::Layout
1965 }
1966 SemanticsRole::Spacer => LayoutNodeKind::Spacer,
1967 SemanticsRole::Button => {
1968 let handler = info
1969 .button_handler
1970 .as_ref()
1971 .cloned()
1972 .unwrap_or_else(|| Rc::new(RefCell::new(|| {})));
1973 LayoutNodeKind::Button { on_click: handler }
1974 }
1975 SemanticsRole::Unknown => LayoutNodeKind::Unknown,
1976 }
1977}
1978
1979fn subtract_padding(constraints: Constraints, padding: EdgeInsets) -> Constraints {
1980 let horizontal = padding.horizontal_sum();
1981 let vertical = padding.vertical_sum();
1982 let min_width = (constraints.min_width - horizontal).max(0.0);
1983 let mut max_width = constraints.max_width;
1984 if max_width.is_finite() {
1985 max_width = (max_width - horizontal).max(0.0);
1986 }
1987 let min_height = (constraints.min_height - vertical).max(0.0);
1988 let mut max_height = constraints.max_height;
1989 if max_height.is_finite() {
1990 max_height = (max_height - vertical).max(0.0);
1991 }
1992 normalize_constraints(Constraints {
1993 min_width,
1994 max_width,
1995 min_height,
1996 max_height,
1997 })
1998}
1999
2000#[cfg(test)]
2001pub(crate) fn align_horizontal(alignment: HorizontalAlignment, available: f32, child: f32) -> f32 {
2002 match alignment {
2003 HorizontalAlignment::Start => 0.0,
2004 HorizontalAlignment::CenterHorizontally => ((available - child) / 2.0).max(0.0),
2005 HorizontalAlignment::End => (available - child).max(0.0),
2006 }
2007}
2008
2009#[cfg(test)]
2010pub(crate) fn align_vertical(alignment: VerticalAlignment, available: f32, child: f32) -> f32 {
2011 match alignment {
2012 VerticalAlignment::Top => 0.0,
2013 VerticalAlignment::CenterVertically => ((available - child) / 2.0).max(0.0),
2014 VerticalAlignment::Bottom => (available - child).max(0.0),
2015 }
2016}
2017
2018fn resolve_dimension(
2019 base: f32,
2020 explicit: DimensionConstraint,
2021 min_override: Option<f32>,
2022 max_override: Option<f32>,
2023 min_limit: f32,
2024 max_limit: f32,
2025) -> f32 {
2026 let mut min_bound = min_limit;
2027 if let Some(min_value) = min_override {
2028 min_bound = min_bound.max(min_value);
2029 }
2030
2031 let mut max_bound = if max_limit.is_finite() {
2032 max_limit
2033 } else {
2034 max_override.unwrap_or(max_limit)
2035 };
2036 if let Some(max_value) = max_override {
2037 if max_bound.is_finite() {
2038 max_bound = max_bound.min(max_value);
2039 } else {
2040 max_bound = max_value;
2041 }
2042 }
2043 if max_bound < min_bound {
2044 max_bound = min_bound;
2045 }
2046
2047 let mut size = match explicit {
2048 DimensionConstraint::Points(points) => points,
2049 DimensionConstraint::Fraction(fraction) => {
2050 if max_limit.is_finite() {
2051 max_limit * fraction.clamp(0.0, 1.0)
2052 } else {
2053 base
2054 }
2055 }
2056 DimensionConstraint::Unspecified => base,
2057 DimensionConstraint::Intrinsic(_) => base,
2060 };
2061
2062 size = clamp_dimension(size, min_bound, max_bound);
2063 size = clamp_dimension(size, min_limit, max_limit);
2064 size.max(0.0)
2065}
2066
2067fn clamp_dimension(value: f32, min: f32, max: f32) -> f32 {
2068 let mut result = value.max(min);
2069 if max.is_finite() {
2070 result = result.min(max);
2071 }
2072 result
2073}
2074
2075fn normalize_constraints(mut constraints: Constraints) -> Constraints {
2076 if constraints.max_width < constraints.min_width {
2077 constraints.max_width = constraints.min_width;
2078 }
2079 if constraints.max_height < constraints.min_height {
2080 constraints.max_height = constraints.min_height;
2081 }
2082 constraints
2083}
2084
2085#[cfg(test)]
2086#[path = "tests/layout_tests.rs"]
2087mod tests;