1pub mod coordinator;
4pub mod core;
5pub mod policies;
6
7use cranpose_core::collections::map::HashMap;
8use std::{
9 cell::{Cell, RefCell},
10 fmt,
11 rc::Rc,
12 sync::atomic::{AtomicU64, Ordering},
13};
14
15use cranpose_core::{
16 Applier, ApplierHost, Composer, ConcreteApplierHost, MemoryApplier, Node, NodeError, NodeId,
17 Phase, RuntimeHandle, SlotTable, SlotsHost, SnapshotStateObserver,
18};
19
20use self::coordinator::NodeCoordinator;
21use self::core::Measurable;
22use self::core::Placeable;
23#[cfg(test)]
24use self::core::{HorizontalAlignment, VerticalAlignment};
25use crate::modifier::{
26 collect_semantics_from_modifier, DimensionConstraint, EdgeInsets, Modifier, ModifierNodeSlices,
27 Point, Rect as GeometryRect, ResolvedModifiers, Size,
28};
29
30use crate::subcompose_layout::SubcomposeLayoutNode;
31use crate::widgets::nodes::{IntrinsicKind, LayoutNode, LayoutNodeCacheHandles};
32use cranpose_foundation::{
33 InvalidationKind, ModifierNodeContext, NodeCapabilities, SemanticsConfiguration,
34};
35use cranpose_ui_layout::{Constraints, MeasurePolicy, MeasureResult};
36
37#[derive(Default)]
42pub(crate) struct LayoutNodeContext {
43 invalidations: Vec<InvalidationKind>,
44 update_requested: bool,
45 active_capabilities: Vec<NodeCapabilities>,
46}
47
48impl LayoutNodeContext {
49 pub(crate) fn new() -> Self {
50 Self::default()
51 }
52
53 pub(crate) fn take_invalidations(&mut self) -> Vec<InvalidationKind> {
54 std::mem::take(&mut self.invalidations)
55 }
56}
57
58impl ModifierNodeContext for LayoutNodeContext {
59 fn invalidate(&mut self, kind: InvalidationKind) {
60 if !self.invalidations.contains(&kind) {
61 self.invalidations.push(kind);
62 }
63 }
64
65 fn request_update(&mut self) {
66 self.update_requested = true;
67 }
68
69 fn push_active_capabilities(&mut self, capabilities: NodeCapabilities) {
70 self.active_capabilities.push(capabilities);
71 }
72
73 fn pop_active_capabilities(&mut self) {
74 self.active_capabilities.pop();
75 }
76}
77
78static NEXT_CACHE_EPOCH: AtomicU64 = AtomicU64::new(1);
79
80#[doc(hidden)]
103pub fn invalidate_all_layout_caches() {
104 NEXT_CACHE_EPOCH.fetch_add(1, Ordering::Relaxed);
105}
106
107struct ApplierSlotGuard<'a> {
118 target: &'a mut MemoryApplier,
120 host: Rc<ConcreteApplierHost<MemoryApplier>>,
122 slots: Rc<RefCell<SlotTable>>,
125}
126
127impl<'a> ApplierSlotGuard<'a> {
128 fn new(target: &'a mut MemoryApplier) -> Self {
132 let original_applier = std::mem::replace(target, MemoryApplier::new());
134 let host = Rc::new(ConcreteApplierHost::new(original_applier));
135
136 let slots = {
138 let mut applier_ref = host.borrow_typed();
139 std::mem::take(applier_ref.slots())
140 };
141 let slots = Rc::new(RefCell::new(slots));
142
143 Self {
144 target,
145 host,
146 slots,
147 }
148 }
149
150 fn host(&self) -> Rc<ConcreteApplierHost<MemoryApplier>> {
152 Rc::clone(&self.host)
153 }
154
155 fn slots_handle(&self) -> Rc<RefCell<SlotTable>> {
158 Rc::clone(&self.slots)
159 }
160}
161
162impl Drop for ApplierSlotGuard<'_> {
163 fn drop(&mut self) {
164 {
168 let mut applier_ref = self.host.borrow_typed();
169 *applier_ref.slots() = std::mem::take(&mut *self.slots.borrow_mut());
170 }
171
172 {
174 let mut applier_ref = self.host.borrow_typed();
175 let original_applier = std::mem::take(&mut *applier_ref);
176 let _ = std::mem::replace(self.target, original_applier);
177 }
178 }
180}
181
182struct ModifierChainMeasurement {
184 result: MeasureResult,
185 content_offset: Point,
187 offset: Point,
189}
190
191type LayoutModifierNodeData = (
192 usize,
193 Rc<RefCell<Box<dyn cranpose_foundation::ModifierNode>>>,
194);
195
196struct ScratchVecPool<T> {
197 available: Vec<Vec<T>>,
198}
199
200impl<T> ScratchVecPool<T> {
201 fn acquire(&mut self) -> Vec<T> {
202 self.available.pop().unwrap_or_default()
203 }
204
205 fn release(&mut self, mut values: Vec<T>) {
206 values.clear();
207 self.available.push(values);
208 }
209
210 #[cfg(test)]
211 fn available_count(&self) -> usize {
212 self.available.len()
213 }
214}
215
216impl<T> Default for ScratchVecPool<T> {
217 fn default() -> Self {
218 Self {
219 available: Vec::new(),
220 }
221 }
222}
223
224#[derive(Clone, Debug, PartialEq, Eq)]
226pub struct SemanticsCallback {
227 node_id: NodeId,
228}
229
230impl SemanticsCallback {
231 pub fn new(node_id: NodeId) -> Self {
232 Self { node_id }
233 }
234
235 pub fn node_id(&self) -> NodeId {
236 self.node_id
237 }
238}
239
240#[derive(Clone, Debug, PartialEq, Eq)]
242pub enum SemanticsAction {
243 Click { handler: SemanticsCallback },
244}
245
246#[derive(Clone, Debug, PartialEq, Eq)]
249pub enum SemanticsRole {
250 Layout,
252 Subcompose,
254 Text { value: String },
256 Spacer,
258 Button,
260 Unknown,
262}
263
264#[derive(Clone, Debug, PartialEq, Eq)]
266pub struct SemanticsNode {
267 pub node_id: NodeId,
268 pub role: SemanticsRole,
269 pub actions: Vec<SemanticsAction>,
270 pub children: Vec<SemanticsNode>,
271 pub description: Option<String>,
272}
273
274impl SemanticsNode {
275 fn new(
276 node_id: NodeId,
277 role: SemanticsRole,
278 actions: Vec<SemanticsAction>,
279 children: Vec<SemanticsNode>,
280 description: Option<String>,
281 ) -> Self {
282 Self {
283 node_id,
284 role,
285 actions,
286 children,
287 description,
288 }
289 }
290}
291
292#[derive(Clone, Debug, PartialEq, Eq)]
294pub struct SemanticsTree {
295 root: SemanticsNode,
296}
297
298impl SemanticsTree {
299 fn new(root: SemanticsNode) -> Self {
300 Self { root }
301 }
302
303 pub fn root(&self) -> &SemanticsNode {
304 &self.root
305 }
306}
307
308#[derive(Debug, Clone)]
310pub struct LayoutTree {
311 root: LayoutBox,
312}
313
314impl LayoutTree {
315 pub fn new(root: LayoutBox) -> Self {
316 Self { root }
317 }
318
319 pub fn root(&self) -> &LayoutBox {
320 &self.root
321 }
322
323 pub fn root_mut(&mut self) -> &mut LayoutBox {
324 &mut self.root
325 }
326
327 pub fn into_root(self) -> LayoutBox {
328 self.root
329 }
330}
331
332#[derive(Debug, Clone)]
334pub struct LayoutBox {
335 pub node_id: NodeId,
336 pub rect: GeometryRect,
337 pub content_offset: Point,
339 pub node_data: LayoutNodeData,
340 pub children: Vec<LayoutBox>,
341}
342
343impl LayoutBox {
344 pub fn new(
345 node_id: NodeId,
346 rect: GeometryRect,
347 content_offset: Point,
348 node_data: LayoutNodeData,
349 children: Vec<LayoutBox>,
350 ) -> Self {
351 Self {
352 node_id,
353 rect,
354 content_offset,
355 node_data,
356 children,
357 }
358 }
359}
360
361#[derive(Debug, Clone)]
363pub struct LayoutNodeData {
364 pub modifier: Modifier,
365 pub resolved_modifiers: ResolvedModifiers,
366 pub modifier_slices: Rc<ModifierNodeSlices>,
367 pub kind: LayoutNodeKind,
368}
369
370impl LayoutNodeData {
371 pub fn new(
372 modifier: Modifier,
373 resolved_modifiers: ResolvedModifiers,
374 modifier_slices: Rc<ModifierNodeSlices>,
375 kind: LayoutNodeKind,
376 ) -> Self {
377 Self {
378 modifier,
379 resolved_modifiers,
380 modifier_slices,
381 kind,
382 }
383 }
384
385 pub fn resolved_modifiers(&self) -> ResolvedModifiers {
386 self.resolved_modifiers
387 }
388
389 pub fn modifier_slices(&self) -> &ModifierNodeSlices {
390 &self.modifier_slices
391 }
392}
393
394#[derive(Clone)]
401pub enum LayoutNodeKind {
402 Layout,
403 Subcompose,
404 Spacer,
405 Button { on_click: Rc<RefCell<dyn FnMut()>> },
406 Unknown,
407}
408
409impl fmt::Debug for LayoutNodeKind {
410 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
411 match self {
412 LayoutNodeKind::Layout => f.write_str("Layout"),
413 LayoutNodeKind::Subcompose => f.write_str("Subcompose"),
414 LayoutNodeKind::Spacer => f.write_str("Spacer"),
415 LayoutNodeKind::Button { .. } => f.write_str("Button"),
416 LayoutNodeKind::Unknown => f.write_str("Unknown"),
417 }
418 }
419}
420
421pub trait LayoutEngine {
423 fn compute_layout(&mut self, root: NodeId, max_size: Size) -> Result<LayoutTree, NodeError>;
424}
425
426impl LayoutEngine for MemoryApplier {
427 fn compute_layout(&mut self, root: NodeId, max_size: Size) -> Result<LayoutTree, NodeError> {
428 let measurements = measure_layout(self, root, max_size)?;
429 Ok(measurements.into_layout_tree())
430 }
431}
432
433#[derive(Debug, Clone)]
435pub struct LayoutMeasurements {
436 root: Rc<MeasuredNode>,
437 semantics: Option<SemanticsTree>,
438 layout_tree: Option<LayoutTree>,
439}
440
441impl LayoutMeasurements {
442 fn new(
443 root: Rc<MeasuredNode>,
444 semantics: Option<SemanticsTree>,
445 layout_tree: Option<LayoutTree>,
446 ) -> Self {
447 Self {
448 root,
449 semantics,
450 layout_tree,
451 }
452 }
453
454 pub fn root_size(&self) -> Size {
456 self.root.size
457 }
458
459 pub fn semantics_tree(&self) -> Option<&SemanticsTree> {
460 self.semantics.as_ref()
461 }
462
463 pub fn into_layout_tree(self) -> LayoutTree {
465 self.layout_tree
466 .expect("layout tree was not built for these measurements")
467 }
468
469 pub fn layout_tree(&self) -> LayoutTree {
471 self.layout_tree
472 .clone()
473 .expect("layout tree was not built for these measurements")
474 }
475}
476
477pub fn build_semantics_tree_from_layout_tree(layout_tree: &LayoutTree) -> SemanticsTree {
482 SemanticsTree::new(build_semantics_node_from_layout_box(layout_tree.root()))
483}
484
485#[derive(Clone, Copy, Debug, PartialEq, Eq)]
486pub struct MeasureLayoutOptions {
487 pub collect_semantics: bool,
488 pub build_layout_tree: bool,
489}
490
491impl Default for MeasureLayoutOptions {
492 fn default() -> Self {
493 Self {
494 collect_semantics: true,
495 build_layout_tree: true,
496 }
497 }
498}
499
500pub fn tree_needs_layout(applier: &mut dyn Applier, root: NodeId) -> Result<bool, NodeError> {
508 Ok(applier.get_mut(root)?.needs_layout())
509}
510
511pub fn tree_needs_semantics(applier: &mut dyn Applier, root: NodeId) -> Result<bool, NodeError> {
517 Ok(applier.get_mut(root)?.needs_semantics())
518}
519
520#[cfg(test)]
522pub(crate) fn bubble_layout_dirty(applier: &mut MemoryApplier, node_id: NodeId) {
523 cranpose_core::bubble_layout_dirty(applier as &mut dyn Applier, node_id);
524}
525
526pub fn measure_layout(
528 applier: &mut MemoryApplier,
529 root: NodeId,
530 max_size: Size,
531) -> Result<LayoutMeasurements, NodeError> {
532 measure_layout_with_options(applier, root, max_size, MeasureLayoutOptions::default())
533}
534
535pub fn measure_layout_with_options(
536 applier: &mut MemoryApplier,
537 root: NodeId,
538 max_size: Size,
539 options: MeasureLayoutOptions,
540) -> Result<LayoutMeasurements, NodeError> {
541 process_pending_layout_repasses(applier, root)?;
542
543 let constraints = Constraints {
544 min_width: 0.0,
545 max_width: max_size.width,
546 min_height: 0.0,
547 max_height: max_size.height,
548 };
549
550 let (needs_remeasure, _needs_semantics, cached_epoch) = match applier
561 .with_node::<LayoutNode, _>(root, |node| {
562 (
563 node.needs_measure(), node.needs_semantics(),
565 node.cache_handles().epoch(),
566 )
567 }) {
568 Ok(tuple) => tuple,
569 Err(NodeError::TypeMismatch { .. }) => {
570 let node = applier.get_mut(root)?;
571 let measure_dirty = node.needs_measure();
575 let semantics_dirty = node.needs_semantics();
576 (measure_dirty, semantics_dirty, 0)
577 }
578 Err(err) => return Err(err),
579 };
580
581 let epoch = if needs_remeasure {
582 NEXT_CACHE_EPOCH.fetch_add(1, Ordering::Relaxed)
583 } else if cached_epoch != 0 {
584 cached_epoch
585 } else {
586 NEXT_CACHE_EPOCH.load(Ordering::Relaxed)
588 };
589
590 let guard = ApplierSlotGuard::new(applier);
598 let applier_host = guard.host();
599 let slots_handle = guard.slots_handle();
600
601 let mut builder =
604 LayoutBuilder::new_with_epoch(Rc::clone(&applier_host), epoch, Rc::clone(&slots_handle));
605
606 let measured = builder.measure_node(root, normalize_constraints(constraints))?;
611
612 if let Ok(mut applier) = applier_host.try_borrow_typed() {
616 if applier
617 .with_node::<LayoutNode, _>(root, |node| {
618 node.set_position(Point::default());
619 })
620 .is_err()
621 {
622 let _ = applier.with_node::<SubcomposeLayoutNode, _>(root, |node| {
623 node.set_position(Point::default());
624 });
625 }
626 }
627
628 let (layout_tree, semantics) = {
629 let mut applier_ref = applier_host.borrow_typed();
630 let layout_tree = if options.build_layout_tree {
631 Some(build_layout_tree(&mut applier_ref, &measured)?)
632 } else {
633 None
634 };
635 let semantics = if options.collect_semantics {
636 let semantics_tree = if let Some(layout_tree) = layout_tree.as_ref() {
637 clear_semantics_dirty_flags(&mut applier_ref, &measured)?;
638 build_semantics_tree_from_layout_tree(layout_tree)
639 } else {
640 build_semantics_tree_from_live_nodes(&mut applier_ref, &measured)?
641 };
642 Some(semantics_tree)
643 } else {
644 None
645 };
646 (layout_tree, semantics)
647 };
648
649 drop(builder);
652
653 Ok(LayoutMeasurements::new(measured, semantics, layout_tree))
657}
658
659fn process_pending_layout_repasses(
660 applier: &mut MemoryApplier,
661 root: NodeId,
662) -> Result<(), NodeError> {
663 let repass_nodes = crate::take_layout_repass_nodes();
664 if repass_nodes.is_empty() {
665 return Ok(());
666 }
667 for node_id in repass_nodes {
668 cranpose_core::bubble_layout_dirty(applier as &mut dyn Applier, node_id);
669 }
670 applier.get_mut(root)?.mark_needs_layout();
671 Ok(())
672}
673
674struct LayoutBuilder {
675 state: Rc<RefCell<LayoutBuilderState>>,
676}
677
678impl LayoutBuilder {
679 fn new_with_epoch(
680 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
681 epoch: u64,
682 slots: Rc<RefCell<SlotTable>>,
683 ) -> Self {
684 Self {
685 state: Rc::new(RefCell::new(LayoutBuilderState::new_with_epoch(
686 applier, epoch, slots,
687 ))),
688 }
689 }
690
691 fn measure_node(
692 &mut self,
693 node_id: NodeId,
694 constraints: Constraints,
695 ) -> Result<Rc<MeasuredNode>, NodeError> {
696 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
697 }
698
699 fn set_runtime_handle(&mut self, handle: Option<RuntimeHandle>) {
700 self.state.borrow_mut().runtime_handle = handle;
701 }
702}
703
704struct LayoutBuilderState {
705 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
706 runtime_handle: Option<RuntimeHandle>,
707 slots: Rc<RefCell<SlotTable>>,
710 cache_epoch: u64,
711 tmp_measurables: ScratchVecPool<Box<dyn Measurable>>,
712 tmp_records: ScratchVecPool<(NodeId, ChildRecord)>,
713 tmp_child_ids: ScratchVecPool<NodeId>,
714 tmp_layout_node_data: ScratchVecPool<LayoutModifierNodeData>,
715}
716
717impl LayoutBuilderState {
718 fn new_with_epoch(
719 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
720 epoch: u64,
721 slots: Rc<RefCell<SlotTable>>,
722 ) -> Self {
723 let runtime_handle = applier.borrow_typed().runtime_handle();
724
725 Self {
726 applier,
727 runtime_handle,
728 slots,
729 cache_epoch: epoch,
730 tmp_measurables: ScratchVecPool::default(),
731 tmp_records: ScratchVecPool::default(),
732 tmp_child_ids: ScratchVecPool::default(),
733 tmp_layout_node_data: ScratchVecPool::default(),
734 }
735 }
736
737 fn try_with_applier_result<R>(
738 state_rc: &Rc<RefCell<Self>>,
739 f: impl FnOnce(&mut MemoryApplier) -> Result<R, NodeError>,
740 ) -> Option<Result<R, NodeError>> {
741 let host = {
742 let state = state_rc.borrow();
743 Rc::clone(&state.applier)
744 };
745
746 let Ok(mut applier) = host.try_borrow_typed() else {
748 return None;
749 };
750
751 Some(f(&mut applier))
752 }
753
754 fn with_applier_result<R>(
755 state_rc: &Rc<RefCell<Self>>,
756 f: impl FnOnce(&mut MemoryApplier) -> Result<R, NodeError>,
757 ) -> Result<R, NodeError> {
758 Self::try_with_applier_result(state_rc, f).unwrap_or_else(|| {
759 Err(NodeError::MissingContext {
760 id: NodeId::default(),
761 reason: "applier already borrowed",
762 })
763 })
764 }
765
766 fn clear_node_placed(state_rc: &Rc<RefCell<Self>>, node_id: NodeId) {
769 let host = {
770 let state = state_rc.borrow();
771 Rc::clone(&state.applier)
772 };
773 let Ok(mut applier) = host.try_borrow_typed() else {
774 return;
775 };
776 if applier
778 .with_node::<LayoutNode, _>(node_id, |node| {
779 node.clear_placed();
780 })
781 .is_err()
782 {
783 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
784 node.clear_placed();
785 });
786 }
787 }
788
789 fn measure_node(
790 state_rc: Rc<RefCell<Self>>,
791 node_id: NodeId,
792 constraints: Constraints,
793 ) -> Result<Rc<MeasuredNode>, NodeError> {
794 Self::clear_node_placed(&state_rc, node_id);
798
799 if let Some(subcompose) =
801 Self::try_measure_subcompose(Rc::clone(&state_rc), node_id, constraints)?
802 {
803 return Ok(subcompose);
804 }
805
806 if let Some(result) = Self::try_with_applier_result(&state_rc, |applier| {
808 match applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
809 LayoutNodeSnapshot::from_layout_node(layout_node)
810 }) {
811 Ok(snapshot) => Ok(Some(snapshot)),
812 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => Ok(None),
813 Err(err) => Err(err),
814 }
815 }) {
816 if let Some(snapshot) = result? {
818 return Self::measure_layout_node(
819 Rc::clone(&state_rc),
820 node_id,
821 snapshot,
822 constraints,
823 );
824 }
825 }
826 Ok(Rc::new(MeasuredNode::new(
831 node_id,
832 Size::default(),
833 Point { x: 0.0, y: 0.0 },
834 Point::default(), Vec::new(),
836 )))
837 }
838
839 fn try_measure_subcompose(
840 state_rc: Rc<RefCell<Self>>,
841 node_id: NodeId,
842 constraints: Constraints,
843 ) -> Result<Option<Rc<MeasuredNode>>, NodeError> {
844 let applier_host = {
845 let state = state_rc.borrow();
846 Rc::clone(&state.applier)
847 };
848
849 let (node_handle, resolved_modifiers) = {
850 let Ok(mut applier) = applier_host.try_borrow_typed() else {
852 return Ok(None);
853 };
854 let node = match applier.get_mut(node_id) {
855 Ok(node) => node,
856 Err(NodeError::Missing { .. }) => return Ok(None),
857 Err(err) => return Err(err),
858 };
859 let any = node.as_any_mut();
860 if let Some(subcompose) =
861 any.downcast_mut::<crate::subcompose_layout::SubcomposeLayoutNode>()
862 {
863 let handle = subcompose.handle();
864 let resolved_modifiers = handle.resolved_modifiers();
865 (handle, resolved_modifiers)
866 } else {
867 return Ok(None);
868 }
869 };
870
871 let runtime_handle = {
872 let mut state = state_rc.borrow_mut();
873 if state.runtime_handle.is_none() {
874 if let Ok(applier) = applier_host.try_borrow_typed() {
876 state.runtime_handle = applier.runtime_handle();
877 }
878 }
879 state
880 .runtime_handle
881 .clone()
882 .ok_or(NodeError::MissingContext {
883 id: node_id,
884 reason: "runtime handle required for subcomposition",
885 })?
886 };
887
888 let props = resolved_modifiers.layout_properties();
889 let padding = resolved_modifiers.padding();
890 let offset = resolved_modifiers.offset();
891 let mut inner_constraints = normalize_constraints(subtract_padding(constraints, padding));
892
893 if let DimensionConstraint::Points(width) = props.width() {
894 let constrained_width = width - padding.horizontal_sum();
895 inner_constraints.max_width = inner_constraints.max_width.min(constrained_width);
896 inner_constraints.min_width = inner_constraints.min_width.min(constrained_width);
897 }
898 if let DimensionConstraint::Points(height) = props.height() {
899 let constrained_height = height - padding.vertical_sum();
900 inner_constraints.max_height = inner_constraints.max_height.min(constrained_height);
901 inner_constraints.min_height = inner_constraints.min_height.min(constrained_height);
902 }
903
904 let mut slots_guard = SlotsGuard::take(Rc::clone(&state_rc));
905 let slots_host = slots_guard.host();
906 let applier_host_dyn: Rc<dyn ApplierHost> = applier_host.clone();
907 let observer = SnapshotStateObserver::new(|callback| callback());
908 let composer = Composer::new(
909 Rc::clone(&slots_host),
910 applier_host_dyn,
911 runtime_handle.clone(),
912 observer,
913 Some(node_id),
914 );
915 composer.enter_phase(Phase::Measure);
916
917 let state_rc_clone = Rc::clone(&state_rc);
918 let measure_error = RefCell::new(None);
919 let state_rc_for_subcompose = Rc::clone(&state_rc_clone);
920 let error_for_subcompose = &measure_error;
921 let measured_children: Rc<RefCell<HashMap<NodeId, Rc<MeasuredNode>>>> =
922 Rc::new(RefCell::new(HashMap::default()));
923 let measured_children_for_subcompose = Rc::clone(&measured_children);
924
925 let measure_result = node_handle.measure(
926 &composer,
927 node_id,
928 inner_constraints,
929 Box::new(
930 move |child_id: NodeId, child_constraints: Constraints| -> Size {
931 match Self::measure_node(
932 Rc::clone(&state_rc_for_subcompose),
933 child_id,
934 child_constraints,
935 ) {
936 Ok(measured) => {
937 measured_children_for_subcompose
938 .borrow_mut()
939 .insert(child_id, Rc::clone(&measured));
940 measured.size
941 }
942 Err(err) => {
943 let mut slot = error_for_subcompose.borrow_mut();
944 if slot.is_none() {
945 *slot = Some(err);
946 }
947 Size::default()
948 }
949 }
950 },
951 ),
952 &measure_error,
953 )?;
954 slots_guard.restore(slots_host.take());
955
956 if let Some(err) = measure_error.borrow_mut().take() {
957 return Err(err);
958 }
959
960 let mut width = measure_result.size.width + padding.horizontal_sum();
964 let mut height = measure_result.size.height + padding.vertical_sum();
965
966 width = resolve_dimension(
967 width,
968 props.width(),
969 props.min_width(),
970 props.max_width(),
971 constraints.min_width,
972 constraints.max_width,
973 );
974 height = resolve_dimension(
975 height,
976 props.height(),
977 props.min_height(),
978 props.max_height(),
979 constraints.min_height,
980 constraints.max_height,
981 );
982
983 let mut children = Vec::with_capacity(measure_result.placements.len());
984 let mut measured_children_by_id = measured_children.borrow_mut();
985
986 if let Ok(mut applier) = applier_host.try_borrow_typed() {
988 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |parent_node| {
989 parent_node.set_measured_size(Size { width, height });
990 parent_node.clear_needs_measure();
991 parent_node.clear_needs_layout();
992 });
993 }
994
995 for placement in measure_result.placements {
996 let child = if let Some(measured) = measured_children_by_id.remove(&placement.node_id) {
997 measured
998 } else {
999 Self::measure_node(Rc::clone(&state_rc), placement.node_id, inner_constraints)?
1005 };
1006 let position = Point {
1007 x: padding.left + placement.x,
1008 y: padding.top + placement.y,
1009 };
1010
1011 if let Ok(mut applier) = applier_host.try_borrow_typed() {
1015 let _ = applier.with_node::<LayoutNode, _>(placement.node_id, |node| {
1016 node.set_position(position);
1017 });
1018 }
1019
1020 children.push(MeasuredChild {
1021 node: child,
1022 offset: position,
1023 });
1024 }
1025
1026 node_handle.set_active_children(children.iter().map(|c| c.node.node_id));
1028
1029 Ok(Some(Rc::new(MeasuredNode::new(
1030 node_id,
1031 Size { width, height },
1032 offset,
1033 Point::default(), children,
1035 ))))
1036 }
1037 fn measure_through_modifier_chain(
1044 state_rc: &Rc<RefCell<Self>>,
1045 node_id: NodeId,
1046 measurables: &[Box<dyn Measurable>],
1047 measure_policy: &Rc<dyn MeasurePolicy>,
1048 constraints: Constraints,
1049 layout_node_data: &mut Vec<LayoutModifierNodeData>,
1050 ) -> ModifierChainMeasurement {
1051 use cranpose_foundation::NodeCapabilities;
1052
1053 layout_node_data.clear();
1055 let mut offset = Point::default();
1056
1057 {
1058 let state = state_rc.borrow();
1059 let mut applier = state.applier.borrow_typed();
1060
1061 let _ = applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1062 let chain_handle = layout_node.modifier_chain();
1063
1064 if !chain_handle.has_layout_nodes() {
1065 return;
1066 }
1067
1068 chain_handle.chain().for_each_forward_matching(
1070 NodeCapabilities::LAYOUT,
1071 |node_ref| {
1072 if let Some(index) = node_ref.entry_index() {
1073 if let Some(node_rc) = chain_handle.chain().get_node_rc(index) {
1075 layout_node_data.push((index, Rc::clone(&node_rc)));
1076 }
1077
1078 node_ref.with_node(|node| {
1082 if let Some(offset_node) =
1083 node.as_any()
1084 .downcast_ref::<crate::modifier_nodes::OffsetNode>()
1085 {
1086 let delta = offset_node.offset();
1087 offset.x += delta.x;
1088 offset.y += delta.y;
1089 }
1090 });
1091 }
1092 },
1093 );
1094 });
1095 }
1096
1097 if layout_node_data.is_empty() {
1100 let result = measure_policy.measure(measurables, constraints);
1101 let final_size = result.size;
1102 let placements = result.placements;
1103
1104 return ModifierChainMeasurement {
1105 result: MeasureResult {
1106 size: final_size,
1107 placements,
1108 },
1109 content_offset: Point::default(),
1110 offset,
1111 };
1112 }
1113
1114 let shared_context = Rc::new(RefCell::new(LayoutNodeContext::new()));
1119
1120 let policy_result = Rc::new(RefCell::new(None));
1122 let inner_coordinator: Box<dyn NodeCoordinator + '_> =
1123 Box::new(coordinator::InnerCoordinator::new(
1124 Rc::clone(measure_policy),
1125 measurables,
1126 Rc::clone(&policy_result),
1127 ));
1128
1129 let mut current_coordinator = inner_coordinator;
1131 while let Some((_, node_rc)) = layout_node_data.pop() {
1132 current_coordinator = Box::new(coordinator::LayoutModifierCoordinator::new(
1133 node_rc,
1134 current_coordinator,
1135 Rc::clone(&shared_context),
1136 ));
1137 }
1138
1139 let placeable = current_coordinator.measure(constraints);
1141 let final_size = Size {
1142 width: placeable.width(),
1143 height: placeable.height(),
1144 };
1145
1146 let content_offset = placeable.content_offset();
1148 let all_placement_offset = Point {
1149 x: content_offset.0,
1150 y: content_offset.1,
1151 };
1152
1153 let content_offset = Point {
1157 x: all_placement_offset.x - offset.x,
1158 y: all_placement_offset.y - offset.y,
1159 };
1160
1161 let placements = policy_result
1164 .borrow_mut()
1165 .take()
1166 .map(|result| result.placements)
1167 .unwrap_or_default();
1168
1169 let invalidations = shared_context.borrow_mut().take_invalidations();
1171 if !invalidations.is_empty() {
1172 Self::with_applier_result(state_rc, |applier| {
1174 applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1175 for kind in invalidations {
1176 match kind {
1177 InvalidationKind::Layout => layout_node.mark_needs_measure(),
1178 InvalidationKind::Draw => layout_node.mark_needs_redraw(),
1179 InvalidationKind::Semantics => layout_node.mark_needs_semantics(),
1180 InvalidationKind::PointerInput => layout_node.mark_needs_pointer_pass(),
1181 InvalidationKind::Focus => layout_node.mark_needs_focus_sync(),
1182 }
1183 }
1184 })
1185 })
1186 .ok();
1187 }
1188
1189 ModifierChainMeasurement {
1190 result: MeasureResult {
1191 size: final_size,
1192 placements,
1193 },
1194 content_offset,
1195 offset,
1196 }
1197 }
1198
1199 fn measure_layout_node(
1200 state_rc: Rc<RefCell<Self>>,
1201 node_id: NodeId,
1202 snapshot: LayoutNodeSnapshot,
1203 constraints: Constraints,
1204 ) -> Result<Rc<MeasuredNode>, NodeError> {
1205 let cache_epoch = {
1206 let state = state_rc.borrow();
1207 state.cache_epoch
1208 };
1209 let LayoutNodeSnapshot {
1210 measure_policy,
1211 cache,
1212 needs_layout,
1213 needs_measure,
1214 } = snapshot;
1215 cache.activate(cache_epoch);
1216
1217 if needs_measure {
1218 }
1220
1221 if !needs_measure && !needs_layout {
1225 if let Some(cached) = cache.get_measurement(constraints) {
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 return Ok(cached);
1236 }
1237 }
1238
1239 let (runtime_handle, applier_host) = {
1240 let state = state_rc.borrow();
1241 (state.runtime_handle.clone(), Rc::clone(&state.applier))
1242 };
1243
1244 let measure_handle = LayoutMeasureHandle::new(Rc::clone(&state_rc));
1245 let error = Rc::new(RefCell::new(None));
1246 let mut pools = VecPools::acquire(Rc::clone(&state_rc));
1247 let (measurables, records, child_ids, layout_node_data) = pools.parts();
1248
1249 applier_host
1250 .borrow_typed()
1251 .with_node::<LayoutNode, _>(node_id, |node| {
1252 child_ids.extend_from_slice(&node.children);
1253 })?;
1254
1255 for &child_id in child_ids.iter() {
1256 let measured = Rc::new(RefCell::new(None));
1257 let position = Rc::new(RefCell::new(None));
1258
1259 let data = {
1260 let mut applier = applier_host.borrow_typed();
1261 match applier.with_node::<LayoutNode, _>(child_id, |n| {
1262 (
1263 n.cache_handles(),
1264 n.layout_state_handle(),
1265 n.needs_layout(),
1266 n.needs_measure(),
1267 )
1268 }) {
1269 Ok((cache, state, needs_layout, needs_measure)) => {
1270 Some((cache, Some(state), needs_layout, needs_measure))
1271 }
1272 Err(NodeError::TypeMismatch { .. }) => {
1273 match applier.with_node::<SubcomposeLayoutNode, _>(child_id, |n| {
1274 (n.needs_layout(), n.needs_measure())
1275 }) {
1276 Ok((needs_layout, needs_measure)) => Some((
1277 LayoutNodeCacheHandles::default(),
1278 None,
1279 needs_layout,
1280 needs_measure,
1281 )),
1282 Err(NodeError::TypeMismatch { .. }) => None,
1283 Err(NodeError::Missing { .. }) => None,
1284 Err(err) => return Err(err),
1285 }
1286 }
1287 Err(NodeError::Missing { .. }) => None,
1288 Err(err) => return Err(err),
1289 }
1290 };
1291
1292 let Some((cache_handles, layout_state, needs_layout, needs_measure)) = data else {
1293 continue;
1294 };
1295
1296 cache_handles.activate(cache_epoch);
1297
1298 records.push((
1299 child_id,
1300 ChildRecord {
1301 measured: Rc::clone(&measured),
1302 last_position: Rc::clone(&position),
1303 },
1304 ));
1305 measurables.push(Box::new(LayoutChildMeasurable::new(
1306 Rc::clone(&applier_host),
1307 child_id,
1308 measured,
1309 position,
1310 Rc::clone(&error),
1311 runtime_handle.clone(),
1312 cache_handles,
1313 cache_epoch,
1314 needs_layout || needs_measure,
1315 Some(measure_handle.clone()),
1316 layout_state,
1317 )));
1318 }
1319
1320 let chain_constraints = constraints;
1321
1322 let modifier_chain_result = Self::measure_through_modifier_chain(
1323 &state_rc,
1324 node_id,
1325 measurables.as_slice(),
1326 &measure_policy,
1327 chain_constraints,
1328 layout_node_data,
1329 );
1330
1331 let (width, height, policy_result, content_offset, offset) = {
1333 let result = modifier_chain_result;
1334 if let Some(err) = error.borrow_mut().take() {
1337 return Err(err);
1338 }
1339
1340 (
1341 result.result.size.width,
1342 result.result.size.height,
1343 result.result,
1344 result.content_offset,
1345 result.offset,
1346 )
1347 };
1348
1349 let mut measured_children = Vec::with_capacity(records.len());
1350 for (child_id, record) in records.iter() {
1351 if let Some(measured) = record.measured.borrow_mut().take() {
1352 let base_position = policy_result
1353 .placements
1354 .iter()
1355 .find(|placement| placement.node_id == *child_id)
1356 .map(|placement| Point {
1357 x: placement.x,
1358 y: placement.y,
1359 })
1360 .or_else(|| record.last_position.borrow().as_ref().copied())
1361 .unwrap_or(Point { x: 0.0, y: 0.0 });
1362 let position = Point {
1364 x: content_offset.x + base_position.x,
1365 y: content_offset.y + base_position.y,
1366 };
1367 measured_children.push(MeasuredChild {
1368 node: measured,
1369 offset: position,
1370 });
1371 }
1372 }
1373
1374 let measured = Rc::new(MeasuredNode::new(
1375 node_id,
1376 Size { width, height },
1377 offset,
1378 content_offset,
1379 measured_children,
1380 ));
1381
1382 cache.store_measurement(constraints, Rc::clone(&measured));
1383
1384 Self::with_applier_result(&state_rc, |applier| {
1386 applier.with_node::<LayoutNode, _>(node_id, |node| {
1387 node.clear_needs_measure();
1388 node.clear_needs_layout();
1389 node.set_measured_size(Size { width, height });
1390 node.set_content_offset(content_offset);
1391 })
1392 })
1393 .ok();
1394
1395 Ok(measured)
1396 }
1397}
1398
1399struct LayoutNodeSnapshot {
1406 measure_policy: Rc<dyn MeasurePolicy>,
1407 cache: LayoutNodeCacheHandles,
1408 needs_layout: bool,
1409 needs_measure: bool,
1411}
1412
1413impl LayoutNodeSnapshot {
1414 fn from_layout_node(node: &LayoutNode) -> Self {
1415 Self {
1416 measure_policy: Rc::clone(&node.measure_policy),
1417 cache: node.cache_handles(),
1418 needs_layout: node.needs_layout(),
1419 needs_measure: node.needs_measure(),
1420 }
1421 }
1422}
1423
1424struct VecPools {
1426 state: Rc<RefCell<LayoutBuilderState>>,
1427 measurables: Option<Vec<Box<dyn Measurable>>>,
1428 records: Option<Vec<(NodeId, ChildRecord)>>,
1429 child_ids: Option<Vec<NodeId>>,
1430 layout_node_data: Option<Vec<LayoutModifierNodeData>>,
1431}
1432
1433impl VecPools {
1434 fn acquire(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1435 let (measurables, records, child_ids, layout_node_data) = {
1436 let mut state_mut = state.borrow_mut();
1437 (
1438 state_mut.tmp_measurables.acquire(),
1439 state_mut.tmp_records.acquire(),
1440 state_mut.tmp_child_ids.acquire(),
1441 state_mut.tmp_layout_node_data.acquire(),
1442 )
1443 };
1444 Self {
1445 state,
1446 measurables: Some(measurables),
1447 records: Some(records),
1448 child_ids: Some(child_ids),
1449 layout_node_data: Some(layout_node_data),
1450 }
1451 }
1452
1453 #[allow(clippy::type_complexity)] fn parts(
1455 &mut self,
1456 ) -> (
1457 &mut Vec<Box<dyn Measurable>>,
1458 &mut Vec<(NodeId, ChildRecord)>,
1459 &mut Vec<NodeId>,
1460 &mut Vec<LayoutModifierNodeData>,
1461 ) {
1462 let measurables = self
1463 .measurables
1464 .as_mut()
1465 .expect("measurables already returned");
1466 let records = self.records.as_mut().expect("records already returned");
1467 let child_ids = self.child_ids.as_mut().expect("child_ids already returned");
1468 let layout_node_data = self
1469 .layout_node_data
1470 .as_mut()
1471 .expect("layout_node_data already returned");
1472 (measurables, records, child_ids, layout_node_data)
1473 }
1474}
1475
1476impl Drop for VecPools {
1477 fn drop(&mut self) {
1478 let mut state = self.state.borrow_mut();
1479 if let Some(measurables) = self.measurables.take() {
1480 state.tmp_measurables.release(measurables);
1481 }
1482 if let Some(records) = self.records.take() {
1483 state.tmp_records.release(records);
1484 }
1485 if let Some(child_ids) = self.child_ids.take() {
1486 state.tmp_child_ids.release(child_ids);
1487 }
1488 if let Some(layout_node_data) = self.layout_node_data.take() {
1489 state.tmp_layout_node_data.release(layout_node_data);
1490 }
1491 }
1492}
1493
1494struct SlotsGuard {
1495 state: Rc<RefCell<LayoutBuilderState>>,
1496 slots: Option<SlotTable>,
1497}
1498
1499impl SlotsGuard {
1500 fn take(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1501 let slots = {
1502 let state_ref = state.borrow();
1503 let mut slots_ref = state_ref.slots.borrow_mut();
1504 std::mem::take(&mut *slots_ref)
1505 };
1506 Self {
1507 state,
1508 slots: Some(slots),
1509 }
1510 }
1511
1512 fn host(&mut self) -> Rc<SlotsHost> {
1513 let slots = self.slots.take().unwrap_or_default();
1514 Rc::new(SlotsHost::new(slots))
1515 }
1516
1517 fn restore(&mut self, slots: SlotTable) {
1518 debug_assert!(self.slots.is_none());
1519 self.slots = Some(slots);
1520 }
1521}
1522
1523impl Drop for SlotsGuard {
1524 fn drop(&mut self) {
1525 if let Some(slots) = self.slots.take() {
1526 let state_ref = self.state.borrow();
1527 *state_ref.slots.borrow_mut() = slots;
1528 }
1529 }
1530}
1531
1532#[derive(Clone)]
1533struct LayoutMeasureHandle {
1534 state: Rc<RefCell<LayoutBuilderState>>,
1535}
1536
1537impl LayoutMeasureHandle {
1538 fn new(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1539 Self { state }
1540 }
1541
1542 fn measure(
1543 &self,
1544 node_id: NodeId,
1545 constraints: Constraints,
1546 ) -> Result<Rc<MeasuredNode>, NodeError> {
1547 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
1548 }
1549}
1550
1551#[derive(Debug, Clone)]
1552pub(crate) struct MeasuredNode {
1553 node_id: NodeId,
1554 size: Size,
1555 offset: Point,
1557 content_offset: Point,
1559 children: Vec<MeasuredChild>,
1560}
1561
1562impl MeasuredNode {
1563 fn new(
1564 node_id: NodeId,
1565 size: Size,
1566 offset: Point,
1567 content_offset: Point,
1568 children: Vec<MeasuredChild>,
1569 ) -> Self {
1570 Self {
1571 node_id,
1572 size,
1573 offset,
1574 content_offset,
1575 children,
1576 }
1577 }
1578}
1579
1580#[derive(Debug, Clone)]
1581struct MeasuredChild {
1582 node: Rc<MeasuredNode>,
1583 offset: Point,
1584}
1585
1586struct ChildRecord {
1587 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1588 last_position: Rc<RefCell<Option<Point>>>,
1589}
1590
1591struct LayoutChildMeasurable {
1592 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1593 node_id: NodeId,
1594 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1595 last_position: Rc<RefCell<Option<Point>>>,
1596 error: Rc<RefCell<Option<NodeError>>>,
1597 runtime_handle: Option<RuntimeHandle>,
1598 cache: LayoutNodeCacheHandles,
1599 cache_epoch: u64,
1600 force_remeasure: Cell<bool>,
1601 measure_handle: Option<LayoutMeasureHandle>,
1602 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1603}
1604
1605impl LayoutChildMeasurable {
1606 #[allow(clippy::too_many_arguments)] fn new(
1608 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1609 node_id: NodeId,
1610 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1611 last_position: Rc<RefCell<Option<Point>>>,
1612 error: Rc<RefCell<Option<NodeError>>>,
1613 runtime_handle: Option<RuntimeHandle>,
1614 cache: LayoutNodeCacheHandles,
1615 cache_epoch: u64,
1616 force_remeasure: bool,
1617 measure_handle: Option<LayoutMeasureHandle>,
1618 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1619 ) -> Self {
1620 cache.activate(cache_epoch);
1621 Self {
1622 applier,
1623 node_id,
1624 measured,
1625 last_position,
1626 error,
1627 runtime_handle,
1628 cache,
1629 cache_epoch,
1630 force_remeasure: Cell::new(force_remeasure),
1631 measure_handle,
1632 layout_state,
1633 }
1634 }
1635
1636 fn record_error(&self, err: NodeError) {
1637 let mut slot = self.error.borrow_mut();
1638 if slot.is_none() {
1639 *slot = Some(err);
1640 }
1641 }
1642
1643 fn perform_measure(&self, constraints: Constraints) -> Result<Rc<MeasuredNode>, NodeError> {
1644 if let Some(handle) = &self.measure_handle {
1645 handle.measure(self.node_id, constraints)
1646 } else {
1647 measure_node_with_host(
1648 Rc::clone(&self.applier),
1649 self.runtime_handle.clone(),
1650 self.node_id,
1651 constraints,
1652 self.cache_epoch,
1653 )
1654 }
1655 }
1656
1657 fn intrinsic_measure(&self, constraints: Constraints) -> Option<Rc<MeasuredNode>> {
1658 self.cache.activate(self.cache_epoch);
1659 if !self.force_remeasure.get() {
1660 if let Some(cached) = self.cache.get_measurement(constraints) {
1661 return Some(cached);
1662 }
1663 }
1664
1665 match self.perform_measure(constraints) {
1666 Ok(measured) => {
1667 self.force_remeasure.set(false);
1668 self.cache
1669 .store_measurement(constraints, Rc::clone(&measured));
1670 Some(measured)
1671 }
1672 Err(err) => {
1673 self.record_error(err);
1674 None
1675 }
1676 }
1677 }
1678}
1679
1680impl Measurable for LayoutChildMeasurable {
1681 fn measure(&self, constraints: Constraints) -> Placeable {
1682 self.cache.activate(self.cache_epoch);
1683 let measured_size;
1684 if !self.force_remeasure.get() {
1685 if let Some(cached) = self.cache.get_measurement(constraints) {
1686 measured_size = cached.size;
1687 *self.measured.borrow_mut() = Some(Rc::clone(&cached));
1688 } else {
1689 match self.perform_measure(constraints) {
1690 Ok(measured) => {
1691 self.force_remeasure.set(false);
1692 measured_size = measured.size;
1693 self.cache
1694 .store_measurement(constraints, Rc::clone(&measured));
1695 *self.measured.borrow_mut() = Some(measured);
1696 }
1697 Err(err) => {
1698 self.record_error(err);
1699 self.measured.borrow_mut().take();
1700 measured_size = Size {
1701 width: 0.0,
1702 height: 0.0,
1703 };
1704 }
1705 }
1706 }
1707 } else {
1708 match self.perform_measure(constraints) {
1709 Ok(measured) => {
1710 self.force_remeasure.set(false);
1711 measured_size = measured.size;
1712 self.cache
1713 .store_measurement(constraints, Rc::clone(&measured));
1714 *self.measured.borrow_mut() = Some(measured);
1715 }
1716 Err(err) => {
1717 self.record_error(err);
1718 self.measured.borrow_mut().take();
1719 measured_size = Size {
1720 width: 0.0,
1721 height: 0.0,
1722 };
1723 }
1724 }
1725 }
1726
1727 if let Some(state) = &self.layout_state {
1730 let mut state = state.borrow_mut();
1731 state.size = measured_size;
1732 state.measurement_constraints = constraints;
1733 } else if let Ok(mut applier) = self.applier.try_borrow_typed() {
1734 let _ = applier.with_node::<LayoutNode, _>(self.node_id, |node| {
1735 node.set_measured_size(measured_size);
1736 node.set_measurement_constraints(constraints);
1737 });
1738 }
1739
1740 let applier = Rc::clone(&self.applier);
1742 let node_id = self.node_id;
1743 let measured = Rc::clone(&self.measured);
1744 let last_position = Rc::clone(&self.last_position);
1745 let layout_state = self.layout_state.clone();
1746
1747 let place_fn = Rc::new(move |x: f32, y: f32| {
1748 let internal_offset = measured
1750 .borrow()
1751 .as_ref()
1752 .map(|m| m.offset)
1753 .unwrap_or_default();
1754
1755 let position = Point {
1756 x: x + internal_offset.x,
1757 y: y + internal_offset.y,
1758 };
1759 *last_position.borrow_mut() = Some(position);
1760
1761 if let Some(state) = &layout_state {
1763 let mut state = state.borrow_mut();
1764 state.position = position;
1765 state.is_placed = true;
1766 } else if let Ok(mut applier) = applier.try_borrow_typed() {
1767 if applier
1768 .with_node::<LayoutNode, _>(node_id, |node| {
1769 node.set_position(position);
1770 })
1771 .is_err()
1772 {
1773 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1774 node.set_position(position);
1775 });
1776 }
1777 }
1778 });
1779
1780 Placeable::with_place_fn(
1781 measured_size.width,
1782 measured_size.height,
1783 self.node_id,
1784 place_fn,
1785 )
1786 }
1787
1788 fn min_intrinsic_width(&self, height: f32) -> f32 {
1789 let kind = IntrinsicKind::MinWidth(height);
1790 self.cache.activate(self.cache_epoch);
1791 if !self.force_remeasure.get() {
1792 if let Some(value) = self.cache.get_intrinsic(&kind) {
1793 return value;
1794 }
1795 }
1796 let constraints = Constraints {
1797 min_width: 0.0,
1798 max_width: f32::INFINITY,
1799 min_height: height,
1800 max_height: height,
1801 };
1802 if let Some(node) = self.intrinsic_measure(constraints) {
1803 let value = node.size.width;
1804 self.cache.store_intrinsic(kind, value);
1805 value
1806 } else {
1807 0.0
1808 }
1809 }
1810
1811 fn max_intrinsic_width(&self, height: f32) -> f32 {
1812 let kind = IntrinsicKind::MaxWidth(height);
1813 self.cache.activate(self.cache_epoch);
1814 if !self.force_remeasure.get() {
1815 if let Some(value) = self.cache.get_intrinsic(&kind) {
1816 return value;
1817 }
1818 }
1819 let constraints = Constraints {
1820 min_width: 0.0,
1821 max_width: f32::INFINITY,
1822 min_height: 0.0,
1823 max_height: height,
1824 };
1825 if let Some(node) = self.intrinsic_measure(constraints) {
1826 let value = node.size.width;
1827 self.cache.store_intrinsic(kind, value);
1828 value
1829 } else {
1830 0.0
1831 }
1832 }
1833
1834 fn min_intrinsic_height(&self, width: f32) -> f32 {
1835 let kind = IntrinsicKind::MinHeight(width);
1836 self.cache.activate(self.cache_epoch);
1837 if !self.force_remeasure.get() {
1838 if let Some(value) = self.cache.get_intrinsic(&kind) {
1839 return value;
1840 }
1841 }
1842 let constraints = Constraints {
1843 min_width: width,
1844 max_width: width,
1845 min_height: 0.0,
1846 max_height: f32::INFINITY,
1847 };
1848 if let Some(node) = self.intrinsic_measure(constraints) {
1849 let value = node.size.height;
1850 self.cache.store_intrinsic(kind, value);
1851 value
1852 } else {
1853 0.0
1854 }
1855 }
1856
1857 fn max_intrinsic_height(&self, width: f32) -> f32 {
1858 let kind = IntrinsicKind::MaxHeight(width);
1859 self.cache.activate(self.cache_epoch);
1860 if !self.force_remeasure.get() {
1861 if let Some(value) = self.cache.get_intrinsic(&kind) {
1862 return value;
1863 }
1864 }
1865 let constraints = Constraints {
1866 min_width: 0.0,
1867 max_width: width,
1868 min_height: 0.0,
1869 max_height: f32::INFINITY,
1870 };
1871 if let Some(node) = self.intrinsic_measure(constraints) {
1872 let value = node.size.height;
1873 self.cache.store_intrinsic(kind, value);
1874 value
1875 } else {
1876 0.0
1877 }
1878 }
1879
1880 fn flex_parent_data(&self) -> Option<cranpose_ui_layout::FlexParentData> {
1881 let Ok(mut applier) = self.applier.try_borrow_typed() else {
1884 return None;
1885 };
1886
1887 applier
1888 .with_node::<LayoutNode, _>(self.node_id, |layout_node| {
1889 let props = layout_node.resolved_modifiers().layout_properties();
1890 props.weight().map(|weight_data| {
1891 cranpose_ui_layout::FlexParentData::new(weight_data.weight, weight_data.fill)
1892 })
1893 })
1894 .ok()
1895 .flatten()
1896 }
1897}
1898
1899fn measure_node_with_host(
1900 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1901 runtime_handle: Option<RuntimeHandle>,
1902 node_id: NodeId,
1903 constraints: Constraints,
1904 epoch: u64,
1905) -> Result<Rc<MeasuredNode>, NodeError> {
1906 let runtime_handle = match runtime_handle {
1907 Some(handle) => Some(handle),
1908 None => applier.borrow_typed().runtime_handle(),
1909 };
1910 let mut builder =
1911 LayoutBuilder::new_with_epoch(applier, epoch, Rc::new(RefCell::new(SlotTable::default())));
1912 builder.set_runtime_handle(runtime_handle);
1913 builder.measure_node(node_id, constraints)
1914}
1915
1916#[derive(Clone)]
1917struct RuntimeNodeMetadata {
1918 modifier: Modifier,
1919 resolved_modifiers: ResolvedModifiers,
1920 modifier_slices: Rc<ModifierNodeSlices>,
1921 role: SemanticsRole,
1922 button_handler: Option<Rc<RefCell<dyn FnMut()>>>,
1923}
1924
1925impl Default for RuntimeNodeMetadata {
1926 fn default() -> Self {
1927 Self {
1928 modifier: Modifier::empty(),
1929 resolved_modifiers: ResolvedModifiers::default(),
1930 modifier_slices: Rc::default(),
1931 role: SemanticsRole::Unknown,
1932 button_handler: None,
1933 }
1934 }
1935}
1936
1937fn role_from_modifier_slices(modifier_slices: &ModifierNodeSlices) -> SemanticsRole {
1938 modifier_slices
1939 .text_content()
1940 .map(|text| SemanticsRole::Text {
1941 value: text.to_string(),
1942 })
1943 .unwrap_or(SemanticsRole::Layout)
1944}
1945
1946fn runtime_metadata_for(
1947 applier: &mut MemoryApplier,
1948 node_id: NodeId,
1949) -> Result<RuntimeNodeMetadata, NodeError> {
1950 if let Ok(meta) = applier.with_node::<LayoutNode, _>(node_id, |layout| {
1955 let modifier = layout.modifier.clone();
1956 let resolved_modifiers = layout.resolved_modifiers();
1957 let modifier_slices = layout.modifier_slices_snapshot();
1958 let role = role_from_modifier_slices(&modifier_slices);
1959
1960 RuntimeNodeMetadata {
1961 modifier,
1962 resolved_modifiers,
1963 modifier_slices,
1964 role,
1965 button_handler: None,
1966 }
1967 }) {
1968 return Ok(meta);
1969 }
1970
1971 if let Ok((modifier, resolved_modifiers, modifier_slices)) = applier
1973 .with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1974 (
1975 node.modifier(),
1976 node.resolved_modifiers(),
1977 node.modifier_slices_snapshot(),
1978 )
1979 })
1980 {
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 clear_semantics_dirty_flags(
1993 applier: &mut MemoryApplier,
1994 node: &MeasuredNode,
1995) -> Result<(), NodeError> {
1996 if let Err(err) = applier.with_node::<LayoutNode, _>(node.node_id, |layout| {
1997 layout.clear_needs_semantics();
1998 }) {
1999 match err {
2000 NodeError::Missing { .. } | NodeError::TypeMismatch { .. } => {}
2001 _ => return Err(err),
2002 }
2003 }
2004
2005 for child in &node.children {
2006 clear_semantics_dirty_flags(applier, &child.node)?;
2007 }
2008
2009 Ok(())
2010}
2011
2012fn build_semantics_tree_from_live_nodes(
2013 applier: &mut MemoryApplier,
2014 node: &MeasuredNode,
2015) -> Result<SemanticsTree, NodeError> {
2016 Ok(SemanticsTree::new(build_semantics_node_from_live_nodes(
2017 applier, node,
2018 )?))
2019}
2020
2021fn semantics_node_from_parts(
2022 node_id: NodeId,
2023 mut role: SemanticsRole,
2024 config: Option<SemanticsConfiguration>,
2025 children: Vec<SemanticsNode>,
2026) -> SemanticsNode {
2027 let mut actions = Vec::new();
2028 let mut description = None;
2029
2030 if let Some(config) = config {
2031 if config.is_button {
2032 role = SemanticsRole::Button;
2033 }
2034 if config.is_clickable {
2035 actions.push(SemanticsAction::Click {
2036 handler: SemanticsCallback::new(node_id),
2037 });
2038 }
2039 description = config.content_description;
2040 }
2041
2042 SemanticsNode::new(node_id, role, actions, children, description)
2043}
2044
2045fn build_semantics_node_from_live_nodes(
2046 applier: &mut MemoryApplier,
2047 node: &MeasuredNode,
2048) -> Result<SemanticsNode, NodeError> {
2049 let (role, config) = match applier.with_node::<LayoutNode, _>(node.node_id, |layout| {
2050 let role = role_from_modifier_slices(&layout.modifier_slices_snapshot());
2051 let config = layout.semantics_configuration();
2052 layout.clear_needs_semantics();
2053 (role, config)
2054 }) {
2055 Ok(data) => data,
2056 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {
2057 match applier.with_node::<SubcomposeLayoutNode, _>(node.node_id, |subcompose| {
2058 (
2059 SemanticsRole::Subcompose,
2060 collect_semantics_from_modifier(&subcompose.modifier()),
2061 )
2062 }) {
2063 Ok(data) => data,
2064 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {
2065 (SemanticsRole::Unknown, None)
2066 }
2067 Err(err) => return Err(err),
2068 }
2069 }
2070 Err(err) => return Err(err),
2071 };
2072
2073 let mut children = Vec::with_capacity(node.children.len());
2074 for child in &node.children {
2075 children.push(build_semantics_node_from_live_nodes(applier, &child.node)?);
2076 }
2077
2078 Ok(semantics_node_from_parts(
2079 node.node_id,
2080 role,
2081 config,
2082 children,
2083 ))
2084}
2085
2086fn build_layout_tree(
2087 applier: &mut MemoryApplier,
2088 node: &MeasuredNode,
2089) -> Result<LayoutTree, NodeError> {
2090 fn place(
2091 applier: &mut MemoryApplier,
2092 node: &MeasuredNode,
2093 origin: Point,
2094 ) -> Result<LayoutBox, NodeError> {
2095 let top_left = Point {
2097 x: origin.x + node.offset.x,
2098 y: origin.y + node.offset.y,
2099 };
2100 let rect = GeometryRect {
2101 x: top_left.x,
2102 y: top_left.y,
2103 width: node.size.width,
2104 height: node.size.height,
2105 };
2106 let info = runtime_metadata_for(applier, node.node_id)?;
2107 let kind = layout_kind_from_metadata(node.node_id, &info);
2108 let RuntimeNodeMetadata {
2109 modifier,
2110 resolved_modifiers,
2111 modifier_slices,
2112 ..
2113 } = info;
2114 let data = LayoutNodeData::new(modifier, resolved_modifiers, modifier_slices, kind);
2115 let mut children = Vec::with_capacity(node.children.len());
2116 for child in &node.children {
2117 let child_origin = Point {
2118 x: top_left.x + child.offset.x,
2119 y: top_left.y + child.offset.y,
2120 };
2121 children.push(place(applier, &child.node, child_origin)?);
2122 }
2123 Ok(LayoutBox::new(
2124 node.node_id,
2125 rect,
2126 node.content_offset,
2127 data,
2128 children,
2129 ))
2130 }
2131
2132 Ok(LayoutTree::new(place(
2133 applier,
2134 node,
2135 Point { x: 0.0, y: 0.0 },
2136 )?))
2137}
2138
2139fn semantics_role_from_layout_box(layout_box: &LayoutBox) -> SemanticsRole {
2140 match &layout_box.node_data.kind {
2141 LayoutNodeKind::Subcompose => SemanticsRole::Subcompose,
2142 LayoutNodeKind::Spacer => SemanticsRole::Spacer,
2143 LayoutNodeKind::Unknown => SemanticsRole::Unknown,
2144 LayoutNodeKind::Button { .. } => SemanticsRole::Button,
2145 LayoutNodeKind::Layout => layout_box
2146 .node_data
2147 .modifier_slices()
2148 .text_content()
2149 .map(|text| SemanticsRole::Text {
2150 value: text.to_string(),
2151 })
2152 .unwrap_or(SemanticsRole::Layout),
2153 }
2154}
2155
2156fn build_semantics_node_from_layout_box(layout_box: &LayoutBox) -> SemanticsNode {
2157 let children = layout_box
2158 .children
2159 .iter()
2160 .map(build_semantics_node_from_layout_box)
2161 .collect();
2162
2163 semantics_node_from_parts(
2164 layout_box.node_id,
2165 semantics_role_from_layout_box(layout_box),
2166 collect_semantics_from_modifier(&layout_box.node_data.modifier),
2167 children,
2168 )
2169}
2170
2171fn layout_kind_from_metadata(_node_id: NodeId, info: &RuntimeNodeMetadata) -> LayoutNodeKind {
2172 match &info.role {
2173 SemanticsRole::Layout => LayoutNodeKind::Layout,
2174 SemanticsRole::Subcompose => LayoutNodeKind::Subcompose,
2175 SemanticsRole::Text { .. } => {
2176 LayoutNodeKind::Layout
2180 }
2181 SemanticsRole::Spacer => LayoutNodeKind::Spacer,
2182 SemanticsRole::Button => {
2183 let handler = info
2184 .button_handler
2185 .as_ref()
2186 .cloned()
2187 .unwrap_or_else(|| Rc::new(RefCell::new(|| {})));
2188 LayoutNodeKind::Button { on_click: handler }
2189 }
2190 SemanticsRole::Unknown => LayoutNodeKind::Unknown,
2191 }
2192}
2193
2194fn subtract_padding(constraints: Constraints, padding: EdgeInsets) -> Constraints {
2195 let horizontal = padding.horizontal_sum();
2196 let vertical = padding.vertical_sum();
2197 let min_width = (constraints.min_width - horizontal).max(0.0);
2198 let mut max_width = constraints.max_width;
2199 if max_width.is_finite() {
2200 max_width = (max_width - horizontal).max(0.0);
2201 }
2202 let min_height = (constraints.min_height - vertical).max(0.0);
2203 let mut max_height = constraints.max_height;
2204 if max_height.is_finite() {
2205 max_height = (max_height - vertical).max(0.0);
2206 }
2207 normalize_constraints(Constraints {
2208 min_width,
2209 max_width,
2210 min_height,
2211 max_height,
2212 })
2213}
2214
2215#[cfg(test)]
2216pub(crate) fn align_horizontal(alignment: HorizontalAlignment, available: f32, child: f32) -> f32 {
2217 match alignment {
2218 HorizontalAlignment::Start => 0.0,
2219 HorizontalAlignment::CenterHorizontally => ((available - child) / 2.0).max(0.0),
2220 HorizontalAlignment::End => (available - child).max(0.0),
2221 }
2222}
2223
2224#[cfg(test)]
2225pub(crate) fn align_vertical(alignment: VerticalAlignment, available: f32, child: f32) -> f32 {
2226 match alignment {
2227 VerticalAlignment::Top => 0.0,
2228 VerticalAlignment::CenterVertically => ((available - child) / 2.0).max(0.0),
2229 VerticalAlignment::Bottom => (available - child).max(0.0),
2230 }
2231}
2232
2233fn resolve_dimension(
2234 base: f32,
2235 explicit: DimensionConstraint,
2236 min_override: Option<f32>,
2237 max_override: Option<f32>,
2238 min_limit: f32,
2239 max_limit: f32,
2240) -> f32 {
2241 let mut min_bound = min_limit;
2242 if let Some(min_value) = min_override {
2243 min_bound = min_bound.max(min_value);
2244 }
2245
2246 let mut max_bound = if max_limit.is_finite() {
2247 max_limit
2248 } else {
2249 max_override.unwrap_or(max_limit)
2250 };
2251 if let Some(max_value) = max_override {
2252 if max_bound.is_finite() {
2253 max_bound = max_bound.min(max_value);
2254 } else {
2255 max_bound = max_value;
2256 }
2257 }
2258 if max_bound < min_bound {
2259 max_bound = min_bound;
2260 }
2261
2262 let mut size = match explicit {
2263 DimensionConstraint::Points(points) => points,
2264 DimensionConstraint::Fraction(fraction) => {
2265 if max_limit.is_finite() {
2266 max_limit * fraction.clamp(0.0, 1.0)
2267 } else {
2268 base
2269 }
2270 }
2271 DimensionConstraint::Unspecified => base,
2272 DimensionConstraint::Intrinsic(_) => base,
2275 };
2276
2277 size = clamp_dimension(size, min_bound, max_bound);
2278 size = clamp_dimension(size, min_limit, max_limit);
2279 size.max(0.0)
2280}
2281
2282fn clamp_dimension(value: f32, min: f32, max: f32) -> f32 {
2283 let mut result = value.max(min);
2284 if max.is_finite() {
2285 result = result.min(max);
2286 }
2287 result
2288}
2289
2290fn normalize_constraints(mut constraints: Constraints) -> Constraints {
2291 if constraints.max_width < constraints.min_width {
2292 constraints.max_width = constraints.min_width;
2293 }
2294 if constraints.max_height < constraints.min_height {
2295 constraints.max_height = constraints.min_height;
2296 }
2297 constraints
2298}
2299
2300#[cfg(test)]
2301#[path = "tests/layout_tests.rs"]
2302mod tests;