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::new(RefCell::new(HashMap::default()));
922 let measured_children_for_subcompose = Rc::clone(&measured_children);
923
924 let measure_result = node_handle.measure(
925 &composer,
926 node_id,
927 inner_constraints,
928 Box::new(
929 move |child_id: NodeId, child_constraints: Constraints| -> Size {
930 match Self::measure_node(
931 Rc::clone(&state_rc_for_subcompose),
932 child_id,
933 child_constraints,
934 ) {
935 Ok(measured) => {
936 measured_children_for_subcompose
937 .borrow_mut()
938 .insert(child_id, Rc::clone(&measured));
939 measured.size
940 }
941 Err(err) => {
942 let mut slot = error_for_subcompose.borrow_mut();
943 if slot.is_none() {
944 *slot = Some(err);
945 }
946 Size::default()
947 }
948 }
949 },
950 ),
951 &measure_error,
952 )?;
953 slots_guard.restore(slots_host.take());
954
955 if let Some(err) = measure_error.borrow_mut().take() {
956 return Err(err);
957 }
958
959 let mut width = measure_result.size.width + padding.horizontal_sum();
963 let mut height = measure_result.size.height + padding.vertical_sum();
964
965 width = resolve_dimension(
966 width,
967 props.width(),
968 props.min_width(),
969 props.max_width(),
970 constraints.min_width,
971 constraints.max_width,
972 );
973 height = resolve_dimension(
974 height,
975 props.height(),
976 props.min_height(),
977 props.max_height(),
978 constraints.min_height,
979 constraints.max_height,
980 );
981
982 let mut children = Vec::with_capacity(measure_result.placements.len());
983 let mut measured_children_by_id = measured_children.borrow_mut();
984
985 if let Ok(mut applier) = applier_host.try_borrow_typed() {
987 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |parent_node| {
988 parent_node.set_measured_size(Size { width, height });
989 parent_node.clear_needs_measure();
990 parent_node.clear_needs_layout();
991 });
992 }
993
994 for placement in measure_result.placements {
995 let child = if let Some(measured) = measured_children_by_id.remove(&placement.node_id) {
996 measured
997 } else {
998 Self::measure_node(Rc::clone(&state_rc), placement.node_id, inner_constraints)?
1004 };
1005 let position = Point {
1006 x: padding.left + placement.x,
1007 y: padding.top + placement.y,
1008 };
1009
1010 if let Ok(mut applier) = applier_host.try_borrow_typed() {
1014 let _ = applier.with_node::<LayoutNode, _>(placement.node_id, |node| {
1015 node.set_position(position);
1016 });
1017 }
1018
1019 children.push(MeasuredChild {
1020 node: child,
1021 offset: position,
1022 });
1023 }
1024
1025 node_handle.set_active_children(children.iter().map(|c| c.node.node_id));
1027
1028 Ok(Some(Rc::new(MeasuredNode::new(
1029 node_id,
1030 Size { width, height },
1031 offset,
1032 Point::default(), children,
1034 ))))
1035 }
1036 fn measure_through_modifier_chain(
1043 state_rc: &Rc<RefCell<Self>>,
1044 node_id: NodeId,
1045 measurables: &[Box<dyn Measurable>],
1046 measure_policy: &Rc<dyn MeasurePolicy>,
1047 constraints: Constraints,
1048 layout_node_data: &mut Vec<LayoutModifierNodeData>,
1049 ) -> ModifierChainMeasurement {
1050 use cranpose_foundation::NodeCapabilities;
1051
1052 layout_node_data.clear();
1054 let mut offset = Point::default();
1055
1056 {
1057 let state = state_rc.borrow();
1058 let mut applier = state.applier.borrow_typed();
1059
1060 let _ = applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1061 let chain_handle = layout_node.modifier_chain();
1062
1063 if !chain_handle.has_layout_nodes() {
1064 return;
1065 }
1066
1067 chain_handle.chain().for_each_forward_matching(
1069 NodeCapabilities::LAYOUT,
1070 |node_ref| {
1071 if let Some(index) = node_ref.entry_index() {
1072 if let Some(node_rc) = chain_handle.chain().get_node_rc(index) {
1074 layout_node_data.push((index, Rc::clone(&node_rc)));
1075 }
1076
1077 node_ref.with_node(|node| {
1081 if let Some(offset_node) =
1082 node.as_any()
1083 .downcast_ref::<crate::modifier_nodes::OffsetNode>()
1084 {
1085 let delta = offset_node.offset();
1086 offset.x += delta.x;
1087 offset.y += delta.y;
1088 }
1089 });
1090 }
1091 },
1092 );
1093 });
1094 }
1095
1096 if layout_node_data.is_empty() {
1099 let result = measure_policy.measure(measurables, constraints);
1100 let final_size = result.size;
1101 let placements = result.placements;
1102
1103 return ModifierChainMeasurement {
1104 result: MeasureResult {
1105 size: final_size,
1106 placements,
1107 },
1108 content_offset: Point::default(),
1109 offset,
1110 };
1111 }
1112
1113 let shared_context = Rc::new(RefCell::new(LayoutNodeContext::new()));
1118
1119 let policy_result = Rc::new(RefCell::new(None));
1121 let inner_coordinator: Box<dyn NodeCoordinator + '_> =
1122 Box::new(coordinator::InnerCoordinator::new(
1123 Rc::clone(measure_policy),
1124 measurables,
1125 Rc::clone(&policy_result),
1126 ));
1127
1128 let mut current_coordinator = inner_coordinator;
1130 while let Some((_, node_rc)) = layout_node_data.pop() {
1131 current_coordinator = Box::new(coordinator::LayoutModifierCoordinator::new(
1132 node_rc,
1133 current_coordinator,
1134 Rc::clone(&shared_context),
1135 ));
1136 }
1137
1138 let placeable = current_coordinator.measure(constraints);
1140 let final_size = Size {
1141 width: placeable.width(),
1142 height: placeable.height(),
1143 };
1144
1145 let content_offset = placeable.content_offset();
1147 let all_placement_offset = Point {
1148 x: content_offset.0,
1149 y: content_offset.1,
1150 };
1151
1152 let content_offset = Point {
1156 x: all_placement_offset.x - offset.x,
1157 y: all_placement_offset.y - offset.y,
1158 };
1159
1160 let placements = policy_result
1163 .borrow_mut()
1164 .take()
1165 .map(|result| result.placements)
1166 .unwrap_or_default();
1167
1168 let invalidations = shared_context.borrow_mut().take_invalidations();
1170 if !invalidations.is_empty() {
1171 Self::with_applier_result(state_rc, |applier| {
1173 applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1174 for kind in invalidations {
1175 match kind {
1176 InvalidationKind::Layout => layout_node.mark_needs_measure(),
1177 InvalidationKind::Draw => layout_node.mark_needs_redraw(),
1178 InvalidationKind::Semantics => layout_node.mark_needs_semantics(),
1179 InvalidationKind::PointerInput => layout_node.mark_needs_pointer_pass(),
1180 InvalidationKind::Focus => layout_node.mark_needs_focus_sync(),
1181 }
1182 }
1183 })
1184 })
1185 .ok();
1186 }
1187
1188 ModifierChainMeasurement {
1189 result: MeasureResult {
1190 size: final_size,
1191 placements,
1192 },
1193 content_offset,
1194 offset,
1195 }
1196 }
1197
1198 fn measure_layout_node(
1199 state_rc: Rc<RefCell<Self>>,
1200 node_id: NodeId,
1201 snapshot: LayoutNodeSnapshot,
1202 constraints: Constraints,
1203 ) -> Result<Rc<MeasuredNode>, NodeError> {
1204 let cache_epoch = {
1205 let state = state_rc.borrow();
1206 state.cache_epoch
1207 };
1208 let LayoutNodeSnapshot {
1209 measure_policy,
1210 cache,
1211 needs_layout,
1212 needs_measure,
1213 } = snapshot;
1214 cache.activate(cache_epoch);
1215
1216 if needs_measure {
1217 }
1219
1220 if !needs_measure && !needs_layout {
1224 if let Some(cached) = cache.get_measurement(constraints) {
1226 Self::with_applier_result(&state_rc, |applier| {
1228 applier.with_node::<LayoutNode, _>(node_id, |node| {
1229 node.clear_needs_measure();
1230 node.clear_needs_layout();
1231 })
1232 })
1233 .ok();
1234 return Ok(cached);
1235 }
1236 }
1237
1238 let (runtime_handle, applier_host) = {
1239 let state = state_rc.borrow();
1240 (state.runtime_handle.clone(), Rc::clone(&state.applier))
1241 };
1242
1243 let measure_handle = LayoutMeasureHandle::new(Rc::clone(&state_rc));
1244 let error = Rc::new(RefCell::new(None));
1245 let mut pools = VecPools::acquire(Rc::clone(&state_rc));
1246 let (measurables, records, child_ids, layout_node_data) = pools.parts();
1247
1248 applier_host
1249 .borrow_typed()
1250 .with_node::<LayoutNode, _>(node_id, |node| {
1251 child_ids.extend_from_slice(&node.children);
1252 })?;
1253
1254 for &child_id in child_ids.iter() {
1255 let measured = Rc::new(RefCell::new(None));
1256 let position = Rc::new(RefCell::new(None));
1257
1258 let data = {
1259 let mut applier = applier_host.borrow_typed();
1260 match applier.with_node::<LayoutNode, _>(child_id, |n| {
1261 (
1262 n.cache_handles(),
1263 n.layout_state_handle(),
1264 n.needs_layout(),
1265 n.needs_measure(),
1266 )
1267 }) {
1268 Ok((cache, state, needs_layout, needs_measure)) => {
1269 Some((cache, Some(state), needs_layout, needs_measure))
1270 }
1271 Err(NodeError::TypeMismatch { .. }) => {
1272 match applier.with_node::<SubcomposeLayoutNode, _>(child_id, |n| {
1273 (n.needs_layout(), n.needs_measure())
1274 }) {
1275 Ok((needs_layout, needs_measure)) => Some((
1276 LayoutNodeCacheHandles::default(),
1277 None,
1278 needs_layout,
1279 needs_measure,
1280 )),
1281 Err(NodeError::TypeMismatch { .. }) => None,
1282 Err(NodeError::Missing { .. }) => None,
1283 Err(err) => return Err(err),
1284 }
1285 }
1286 Err(NodeError::Missing { .. }) => None,
1287 Err(err) => return Err(err),
1288 }
1289 };
1290
1291 let Some((cache_handles, layout_state, needs_layout, needs_measure)) = data else {
1292 continue;
1293 };
1294
1295 cache_handles.activate(cache_epoch);
1296
1297 records.push((
1298 child_id,
1299 ChildRecord {
1300 measured: Rc::clone(&measured),
1301 last_position: Rc::clone(&position),
1302 },
1303 ));
1304 measurables.push(Box::new(LayoutChildMeasurable::new(
1305 Rc::clone(&applier_host),
1306 child_id,
1307 measured,
1308 position,
1309 Rc::clone(&error),
1310 runtime_handle.clone(),
1311 cache_handles,
1312 cache_epoch,
1313 needs_layout || needs_measure,
1314 Some(measure_handle.clone()),
1315 layout_state,
1316 )));
1317 }
1318
1319 let chain_constraints = constraints;
1320
1321 let modifier_chain_result = Self::measure_through_modifier_chain(
1322 &state_rc,
1323 node_id,
1324 measurables.as_slice(),
1325 &measure_policy,
1326 chain_constraints,
1327 layout_node_data,
1328 );
1329
1330 let (width, height, policy_result, content_offset, offset) = {
1332 let result = modifier_chain_result;
1333 if let Some(err) = error.borrow_mut().take() {
1336 return Err(err);
1337 }
1338
1339 (
1340 result.result.size.width,
1341 result.result.size.height,
1342 result.result,
1343 result.content_offset,
1344 result.offset,
1345 )
1346 };
1347
1348 let mut measured_children = Vec::with_capacity(records.len());
1349 for (child_id, record) in records.iter() {
1350 if let Some(measured) = record.measured.borrow_mut().take() {
1351 let base_position = policy_result
1352 .placements
1353 .iter()
1354 .find(|placement| placement.node_id == *child_id)
1355 .map(|placement| Point {
1356 x: placement.x,
1357 y: placement.y,
1358 })
1359 .or_else(|| record.last_position.borrow().as_ref().copied())
1360 .unwrap_or(Point { x: 0.0, y: 0.0 });
1361 let position = Point {
1363 x: content_offset.x + base_position.x,
1364 y: content_offset.y + base_position.y,
1365 };
1366 measured_children.push(MeasuredChild {
1367 node: measured,
1368 offset: position,
1369 });
1370 }
1371 }
1372
1373 let measured = Rc::new(MeasuredNode::new(
1374 node_id,
1375 Size { width, height },
1376 offset,
1377 content_offset,
1378 measured_children,
1379 ));
1380
1381 cache.store_measurement(constraints, Rc::clone(&measured));
1382
1383 Self::with_applier_result(&state_rc, |applier| {
1385 applier.with_node::<LayoutNode, _>(node_id, |node| {
1386 node.clear_needs_measure();
1387 node.clear_needs_layout();
1388 node.set_measured_size(Size { width, height });
1389 node.set_content_offset(content_offset);
1390 })
1391 })
1392 .ok();
1393
1394 Ok(measured)
1395 }
1396}
1397
1398struct LayoutNodeSnapshot {
1405 measure_policy: Rc<dyn MeasurePolicy>,
1406 cache: LayoutNodeCacheHandles,
1407 needs_layout: bool,
1408 needs_measure: bool,
1410}
1411
1412impl LayoutNodeSnapshot {
1413 fn from_layout_node(node: &LayoutNode) -> Self {
1414 Self {
1415 measure_policy: Rc::clone(&node.measure_policy),
1416 cache: node.cache_handles(),
1417 needs_layout: node.needs_layout(),
1418 needs_measure: node.needs_measure(),
1419 }
1420 }
1421}
1422
1423struct VecPools {
1425 state: Rc<RefCell<LayoutBuilderState>>,
1426 measurables: Option<Vec<Box<dyn Measurable>>>,
1427 records: Option<Vec<(NodeId, ChildRecord)>>,
1428 child_ids: Option<Vec<NodeId>>,
1429 layout_node_data: Option<Vec<LayoutModifierNodeData>>,
1430}
1431
1432impl VecPools {
1433 fn acquire(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1434 let (measurables, records, child_ids, layout_node_data) = {
1435 let mut state_mut = state.borrow_mut();
1436 (
1437 state_mut.tmp_measurables.acquire(),
1438 state_mut.tmp_records.acquire(),
1439 state_mut.tmp_child_ids.acquire(),
1440 state_mut.tmp_layout_node_data.acquire(),
1441 )
1442 };
1443 Self {
1444 state,
1445 measurables: Some(measurables),
1446 records: Some(records),
1447 child_ids: Some(child_ids),
1448 layout_node_data: Some(layout_node_data),
1449 }
1450 }
1451
1452 #[allow(clippy::type_complexity)] fn parts(
1454 &mut self,
1455 ) -> (
1456 &mut Vec<Box<dyn Measurable>>,
1457 &mut Vec<(NodeId, ChildRecord)>,
1458 &mut Vec<NodeId>,
1459 &mut Vec<LayoutModifierNodeData>,
1460 ) {
1461 let measurables = self
1462 .measurables
1463 .as_mut()
1464 .expect("measurables already returned");
1465 let records = self.records.as_mut().expect("records already returned");
1466 let child_ids = self.child_ids.as_mut().expect("child_ids already returned");
1467 let layout_node_data = self
1468 .layout_node_data
1469 .as_mut()
1470 .expect("layout_node_data already returned");
1471 (measurables, records, child_ids, layout_node_data)
1472 }
1473}
1474
1475impl Drop for VecPools {
1476 fn drop(&mut self) {
1477 let mut state = self.state.borrow_mut();
1478 if let Some(measurables) = self.measurables.take() {
1479 state.tmp_measurables.release(measurables);
1480 }
1481 if let Some(records) = self.records.take() {
1482 state.tmp_records.release(records);
1483 }
1484 if let Some(child_ids) = self.child_ids.take() {
1485 state.tmp_child_ids.release(child_ids);
1486 }
1487 if let Some(layout_node_data) = self.layout_node_data.take() {
1488 state.tmp_layout_node_data.release(layout_node_data);
1489 }
1490 }
1491}
1492
1493struct SlotsGuard {
1494 state: Rc<RefCell<LayoutBuilderState>>,
1495 slots: Option<SlotTable>,
1496}
1497
1498impl SlotsGuard {
1499 fn take(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1500 let slots = {
1501 let state_ref = state.borrow();
1502 let mut slots_ref = state_ref.slots.borrow_mut();
1503 std::mem::take(&mut *slots_ref)
1504 };
1505 Self {
1506 state,
1507 slots: Some(slots),
1508 }
1509 }
1510
1511 fn host(&mut self) -> Rc<SlotsHost> {
1512 let slots = self.slots.take().unwrap_or_default();
1513 Rc::new(SlotsHost::new(slots))
1514 }
1515
1516 fn restore(&mut self, slots: SlotTable) {
1517 debug_assert!(self.slots.is_none());
1518 self.slots = Some(slots);
1519 }
1520}
1521
1522impl Drop for SlotsGuard {
1523 fn drop(&mut self) {
1524 if let Some(slots) = self.slots.take() {
1525 let state_ref = self.state.borrow();
1526 *state_ref.slots.borrow_mut() = slots;
1527 }
1528 }
1529}
1530
1531#[derive(Clone)]
1532struct LayoutMeasureHandle {
1533 state: Rc<RefCell<LayoutBuilderState>>,
1534}
1535
1536impl LayoutMeasureHandle {
1537 fn new(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1538 Self { state }
1539 }
1540
1541 fn measure(
1542 &self,
1543 node_id: NodeId,
1544 constraints: Constraints,
1545 ) -> Result<Rc<MeasuredNode>, NodeError> {
1546 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
1547 }
1548}
1549
1550#[derive(Debug, Clone)]
1551pub(crate) struct MeasuredNode {
1552 node_id: NodeId,
1553 size: Size,
1554 offset: Point,
1556 content_offset: Point,
1558 children: Vec<MeasuredChild>,
1559}
1560
1561impl MeasuredNode {
1562 fn new(
1563 node_id: NodeId,
1564 size: Size,
1565 offset: Point,
1566 content_offset: Point,
1567 children: Vec<MeasuredChild>,
1568 ) -> Self {
1569 Self {
1570 node_id,
1571 size,
1572 offset,
1573 content_offset,
1574 children,
1575 }
1576 }
1577}
1578
1579#[derive(Debug, Clone)]
1580struct MeasuredChild {
1581 node: Rc<MeasuredNode>,
1582 offset: Point,
1583}
1584
1585struct ChildRecord {
1586 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1587 last_position: Rc<RefCell<Option<Point>>>,
1588}
1589
1590struct LayoutChildMeasurable {
1591 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1592 node_id: NodeId,
1593 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1594 last_position: Rc<RefCell<Option<Point>>>,
1595 error: Rc<RefCell<Option<NodeError>>>,
1596 runtime_handle: Option<RuntimeHandle>,
1597 cache: LayoutNodeCacheHandles,
1598 cache_epoch: u64,
1599 force_remeasure: Cell<bool>,
1600 measure_handle: Option<LayoutMeasureHandle>,
1601 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1602}
1603
1604impl LayoutChildMeasurable {
1605 #[allow(clippy::too_many_arguments)] fn new(
1607 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1608 node_id: NodeId,
1609 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1610 last_position: Rc<RefCell<Option<Point>>>,
1611 error: Rc<RefCell<Option<NodeError>>>,
1612 runtime_handle: Option<RuntimeHandle>,
1613 cache: LayoutNodeCacheHandles,
1614 cache_epoch: u64,
1615 force_remeasure: bool,
1616 measure_handle: Option<LayoutMeasureHandle>,
1617 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1618 ) -> Self {
1619 cache.activate(cache_epoch);
1620 Self {
1621 applier,
1622 node_id,
1623 measured,
1624 last_position,
1625 error,
1626 runtime_handle,
1627 cache,
1628 cache_epoch,
1629 force_remeasure: Cell::new(force_remeasure),
1630 measure_handle,
1631 layout_state,
1632 }
1633 }
1634
1635 fn record_error(&self, err: NodeError) {
1636 let mut slot = self.error.borrow_mut();
1637 if slot.is_none() {
1638 *slot = Some(err);
1639 }
1640 }
1641
1642 fn perform_measure(&self, constraints: Constraints) -> Result<Rc<MeasuredNode>, NodeError> {
1643 if let Some(handle) = &self.measure_handle {
1644 handle.measure(self.node_id, constraints)
1645 } else {
1646 measure_node_with_host(
1647 Rc::clone(&self.applier),
1648 self.runtime_handle.clone(),
1649 self.node_id,
1650 constraints,
1651 self.cache_epoch,
1652 )
1653 }
1654 }
1655
1656 fn intrinsic_measure(&self, constraints: Constraints) -> Option<Rc<MeasuredNode>> {
1657 self.cache.activate(self.cache_epoch);
1658 if !self.force_remeasure.get() {
1659 if let Some(cached) = self.cache.get_measurement(constraints) {
1660 return Some(cached);
1661 }
1662 }
1663
1664 match self.perform_measure(constraints) {
1665 Ok(measured) => {
1666 self.force_remeasure.set(false);
1667 self.cache
1668 .store_measurement(constraints, Rc::clone(&measured));
1669 Some(measured)
1670 }
1671 Err(err) => {
1672 self.record_error(err);
1673 None
1674 }
1675 }
1676 }
1677}
1678
1679impl Measurable for LayoutChildMeasurable {
1680 fn measure(&self, constraints: Constraints) -> Placeable {
1681 self.cache.activate(self.cache_epoch);
1682 let measured_size;
1683 if !self.force_remeasure.get() {
1684 if let Some(cached) = self.cache.get_measurement(constraints) {
1685 measured_size = cached.size;
1686 *self.measured.borrow_mut() = Some(Rc::clone(&cached));
1687 } else {
1688 match self.perform_measure(constraints) {
1689 Ok(measured) => {
1690 self.force_remeasure.set(false);
1691 measured_size = measured.size;
1692 self.cache
1693 .store_measurement(constraints, Rc::clone(&measured));
1694 *self.measured.borrow_mut() = Some(measured);
1695 }
1696 Err(err) => {
1697 self.record_error(err);
1698 self.measured.borrow_mut().take();
1699 measured_size = Size {
1700 width: 0.0,
1701 height: 0.0,
1702 };
1703 }
1704 }
1705 }
1706 } else {
1707 match self.perform_measure(constraints) {
1708 Ok(measured) => {
1709 self.force_remeasure.set(false);
1710 measured_size = measured.size;
1711 self.cache
1712 .store_measurement(constraints, Rc::clone(&measured));
1713 *self.measured.borrow_mut() = Some(measured);
1714 }
1715 Err(err) => {
1716 self.record_error(err);
1717 self.measured.borrow_mut().take();
1718 measured_size = Size {
1719 width: 0.0,
1720 height: 0.0,
1721 };
1722 }
1723 }
1724 }
1725
1726 if let Some(state) = &self.layout_state {
1729 let mut state = state.borrow_mut();
1730 state.size = measured_size;
1731 state.measurement_constraints = constraints;
1732 } else if let Ok(mut applier) = self.applier.try_borrow_typed() {
1733 let _ = applier.with_node::<LayoutNode, _>(self.node_id, |node| {
1734 node.set_measured_size(measured_size);
1735 node.set_measurement_constraints(constraints);
1736 });
1737 }
1738
1739 let applier = Rc::clone(&self.applier);
1741 let node_id = self.node_id;
1742 let measured = Rc::clone(&self.measured);
1743 let last_position = Rc::clone(&self.last_position);
1744 let layout_state = self.layout_state.clone();
1745
1746 let place_fn = Rc::new(move |x: f32, y: f32| {
1747 let internal_offset = measured
1749 .borrow()
1750 .as_ref()
1751 .map(|m| m.offset)
1752 .unwrap_or_default();
1753
1754 let position = Point {
1755 x: x + internal_offset.x,
1756 y: y + internal_offset.y,
1757 };
1758 *last_position.borrow_mut() = Some(position);
1759
1760 if let Some(state) = &layout_state {
1762 let mut state = state.borrow_mut();
1763 state.position = position;
1764 state.is_placed = true;
1765 } else if let Ok(mut applier) = applier.try_borrow_typed() {
1766 if applier
1767 .with_node::<LayoutNode, _>(node_id, |node| {
1768 node.set_position(position);
1769 })
1770 .is_err()
1771 {
1772 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1773 node.set_position(position);
1774 });
1775 }
1776 }
1777 });
1778
1779 Placeable::with_place_fn(
1780 measured_size.width,
1781 measured_size.height,
1782 self.node_id,
1783 place_fn,
1784 )
1785 }
1786
1787 fn min_intrinsic_width(&self, height: f32) -> f32 {
1788 let kind = IntrinsicKind::MinWidth(height);
1789 self.cache.activate(self.cache_epoch);
1790 if !self.force_remeasure.get() {
1791 if let Some(value) = self.cache.get_intrinsic(&kind) {
1792 return value;
1793 }
1794 }
1795 let constraints = Constraints {
1796 min_width: 0.0,
1797 max_width: f32::INFINITY,
1798 min_height: height,
1799 max_height: height,
1800 };
1801 if let Some(node) = self.intrinsic_measure(constraints) {
1802 let value = node.size.width;
1803 self.cache.store_intrinsic(kind, value);
1804 value
1805 } else {
1806 0.0
1807 }
1808 }
1809
1810 fn max_intrinsic_width(&self, height: f32) -> f32 {
1811 let kind = IntrinsicKind::MaxWidth(height);
1812 self.cache.activate(self.cache_epoch);
1813 if !self.force_remeasure.get() {
1814 if let Some(value) = self.cache.get_intrinsic(&kind) {
1815 return value;
1816 }
1817 }
1818 let constraints = Constraints {
1819 min_width: 0.0,
1820 max_width: f32::INFINITY,
1821 min_height: 0.0,
1822 max_height: height,
1823 };
1824 if let Some(node) = self.intrinsic_measure(constraints) {
1825 let value = node.size.width;
1826 self.cache.store_intrinsic(kind, value);
1827 value
1828 } else {
1829 0.0
1830 }
1831 }
1832
1833 fn min_intrinsic_height(&self, width: f32) -> f32 {
1834 let kind = IntrinsicKind::MinHeight(width);
1835 self.cache.activate(self.cache_epoch);
1836 if !self.force_remeasure.get() {
1837 if let Some(value) = self.cache.get_intrinsic(&kind) {
1838 return value;
1839 }
1840 }
1841 let constraints = Constraints {
1842 min_width: width,
1843 max_width: width,
1844 min_height: 0.0,
1845 max_height: f32::INFINITY,
1846 };
1847 if let Some(node) = self.intrinsic_measure(constraints) {
1848 let value = node.size.height;
1849 self.cache.store_intrinsic(kind, value);
1850 value
1851 } else {
1852 0.0
1853 }
1854 }
1855
1856 fn max_intrinsic_height(&self, width: f32) -> f32 {
1857 let kind = IntrinsicKind::MaxHeight(width);
1858 self.cache.activate(self.cache_epoch);
1859 if !self.force_remeasure.get() {
1860 if let Some(value) = self.cache.get_intrinsic(&kind) {
1861 return value;
1862 }
1863 }
1864 let constraints = Constraints {
1865 min_width: 0.0,
1866 max_width: width,
1867 min_height: 0.0,
1868 max_height: f32::INFINITY,
1869 };
1870 if let Some(node) = self.intrinsic_measure(constraints) {
1871 let value = node.size.height;
1872 self.cache.store_intrinsic(kind, value);
1873 value
1874 } else {
1875 0.0
1876 }
1877 }
1878
1879 fn flex_parent_data(&self) -> Option<cranpose_ui_layout::FlexParentData> {
1880 let Ok(mut applier) = self.applier.try_borrow_typed() else {
1883 return None;
1884 };
1885
1886 applier
1887 .with_node::<LayoutNode, _>(self.node_id, |layout_node| {
1888 let props = layout_node.resolved_modifiers().layout_properties();
1889 props.weight().map(|weight_data| {
1890 cranpose_ui_layout::FlexParentData::new(weight_data.weight, weight_data.fill)
1891 })
1892 })
1893 .ok()
1894 .flatten()
1895 }
1896}
1897
1898fn measure_node_with_host(
1899 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1900 runtime_handle: Option<RuntimeHandle>,
1901 node_id: NodeId,
1902 constraints: Constraints,
1903 epoch: u64,
1904) -> Result<Rc<MeasuredNode>, NodeError> {
1905 let runtime_handle = match runtime_handle {
1906 Some(handle) => Some(handle),
1907 None => applier.borrow_typed().runtime_handle(),
1908 };
1909 let mut builder =
1910 LayoutBuilder::new_with_epoch(applier, epoch, Rc::new(RefCell::new(SlotTable::default())));
1911 builder.set_runtime_handle(runtime_handle);
1912 builder.measure_node(node_id, constraints)
1913}
1914
1915#[derive(Clone)]
1916struct RuntimeNodeMetadata {
1917 modifier: Modifier,
1918 resolved_modifiers: ResolvedModifiers,
1919 modifier_slices: Rc<ModifierNodeSlices>,
1920 role: SemanticsRole,
1921 button_handler: Option<Rc<RefCell<dyn FnMut()>>>,
1922}
1923
1924impl Default for RuntimeNodeMetadata {
1925 fn default() -> Self {
1926 Self {
1927 modifier: Modifier::empty(),
1928 resolved_modifiers: ResolvedModifiers::default(),
1929 modifier_slices: Rc::default(),
1930 role: SemanticsRole::Unknown,
1931 button_handler: None,
1932 }
1933 }
1934}
1935
1936fn role_from_modifier_slices(modifier_slices: &ModifierNodeSlices) -> SemanticsRole {
1937 modifier_slices
1938 .text_content()
1939 .map(|text| SemanticsRole::Text {
1940 value: text.to_string(),
1941 })
1942 .unwrap_or(SemanticsRole::Layout)
1943}
1944
1945fn runtime_metadata_for(
1946 applier: &mut MemoryApplier,
1947 node_id: NodeId,
1948) -> Result<RuntimeNodeMetadata, NodeError> {
1949 if let Ok(meta) = applier.with_node::<LayoutNode, _>(node_id, |layout| {
1954 let modifier = layout.modifier.clone();
1955 let resolved_modifiers = layout.resolved_modifiers();
1956 let modifier_slices = layout.modifier_slices_snapshot();
1957 let role = role_from_modifier_slices(&modifier_slices);
1958
1959 RuntimeNodeMetadata {
1960 modifier,
1961 resolved_modifiers,
1962 modifier_slices,
1963 role,
1964 button_handler: None,
1965 }
1966 }) {
1967 return Ok(meta);
1968 }
1969
1970 if let Ok((modifier, resolved_modifiers, modifier_slices)) = applier
1972 .with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1973 (
1974 node.modifier(),
1975 node.resolved_modifiers(),
1976 node.modifier_slices_snapshot(),
1977 )
1978 })
1979 {
1980 return Ok(RuntimeNodeMetadata {
1981 modifier,
1982 resolved_modifiers,
1983 modifier_slices,
1984 role: SemanticsRole::Subcompose,
1985 button_handler: None,
1986 });
1987 }
1988 Ok(RuntimeNodeMetadata::default())
1989}
1990
1991fn clear_semantics_dirty_flags(
1992 applier: &mut MemoryApplier,
1993 node: &MeasuredNode,
1994) -> Result<(), NodeError> {
1995 if let Err(err) = applier.with_node::<LayoutNode, _>(node.node_id, |layout| {
1996 layout.clear_needs_semantics();
1997 }) {
1998 match err {
1999 NodeError::Missing { .. } | NodeError::TypeMismatch { .. } => {}
2000 _ => return Err(err),
2001 }
2002 }
2003
2004 for child in &node.children {
2005 clear_semantics_dirty_flags(applier, &child.node)?;
2006 }
2007
2008 Ok(())
2009}
2010
2011fn build_semantics_tree_from_live_nodes(
2012 applier: &mut MemoryApplier,
2013 node: &MeasuredNode,
2014) -> Result<SemanticsTree, NodeError> {
2015 Ok(SemanticsTree::new(build_semantics_node_from_live_nodes(
2016 applier, node,
2017 )?))
2018}
2019
2020fn semantics_node_from_parts(
2021 node_id: NodeId,
2022 mut role: SemanticsRole,
2023 config: Option<SemanticsConfiguration>,
2024 children: Vec<SemanticsNode>,
2025) -> SemanticsNode {
2026 let mut actions = Vec::new();
2027 let mut description = None;
2028
2029 if let Some(config) = config {
2030 if config.is_button {
2031 role = SemanticsRole::Button;
2032 }
2033 if config.is_clickable {
2034 actions.push(SemanticsAction::Click {
2035 handler: SemanticsCallback::new(node_id),
2036 });
2037 }
2038 description = config.content_description;
2039 }
2040
2041 SemanticsNode::new(node_id, role, actions, children, description)
2042}
2043
2044fn build_semantics_node_from_live_nodes(
2045 applier: &mut MemoryApplier,
2046 node: &MeasuredNode,
2047) -> Result<SemanticsNode, NodeError> {
2048 let (role, config) = match applier.with_node::<LayoutNode, _>(node.node_id, |layout| {
2049 let role = role_from_modifier_slices(&layout.modifier_slices_snapshot());
2050 let config = layout.semantics_configuration();
2051 layout.clear_needs_semantics();
2052 (role, config)
2053 }) {
2054 Ok(data) => data,
2055 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {
2056 match applier.with_node::<SubcomposeLayoutNode, _>(node.node_id, |subcompose| {
2057 (
2058 SemanticsRole::Subcompose,
2059 collect_semantics_from_modifier(&subcompose.modifier()),
2060 )
2061 }) {
2062 Ok(data) => data,
2063 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {
2064 (SemanticsRole::Unknown, None)
2065 }
2066 Err(err) => return Err(err),
2067 }
2068 }
2069 Err(err) => return Err(err),
2070 };
2071
2072 let mut children = Vec::with_capacity(node.children.len());
2073 for child in &node.children {
2074 children.push(build_semantics_node_from_live_nodes(applier, &child.node)?);
2075 }
2076
2077 Ok(semantics_node_from_parts(
2078 node.node_id,
2079 role,
2080 config,
2081 children,
2082 ))
2083}
2084
2085fn build_layout_tree(
2086 applier: &mut MemoryApplier,
2087 node: &MeasuredNode,
2088) -> Result<LayoutTree, NodeError> {
2089 fn place(
2090 applier: &mut MemoryApplier,
2091 node: &MeasuredNode,
2092 origin: Point,
2093 ) -> Result<LayoutBox, NodeError> {
2094 let top_left = Point {
2096 x: origin.x + node.offset.x,
2097 y: origin.y + node.offset.y,
2098 };
2099 let rect = GeometryRect {
2100 x: top_left.x,
2101 y: top_left.y,
2102 width: node.size.width,
2103 height: node.size.height,
2104 };
2105 let info = runtime_metadata_for(applier, node.node_id)?;
2106 let kind = layout_kind_from_metadata(node.node_id, &info);
2107 let RuntimeNodeMetadata {
2108 modifier,
2109 resolved_modifiers,
2110 modifier_slices,
2111 ..
2112 } = info;
2113 let data = LayoutNodeData::new(modifier, resolved_modifiers, modifier_slices, kind);
2114 let mut children = Vec::with_capacity(node.children.len());
2115 for child in &node.children {
2116 let child_origin = Point {
2117 x: top_left.x + child.offset.x,
2118 y: top_left.y + child.offset.y,
2119 };
2120 children.push(place(applier, &child.node, child_origin)?);
2121 }
2122 Ok(LayoutBox::new(
2123 node.node_id,
2124 rect,
2125 node.content_offset,
2126 data,
2127 children,
2128 ))
2129 }
2130
2131 Ok(LayoutTree::new(place(
2132 applier,
2133 node,
2134 Point { x: 0.0, y: 0.0 },
2135 )?))
2136}
2137
2138fn semantics_role_from_layout_box(layout_box: &LayoutBox) -> SemanticsRole {
2139 match &layout_box.node_data.kind {
2140 LayoutNodeKind::Subcompose => SemanticsRole::Subcompose,
2141 LayoutNodeKind::Spacer => SemanticsRole::Spacer,
2142 LayoutNodeKind::Unknown => SemanticsRole::Unknown,
2143 LayoutNodeKind::Button { .. } => SemanticsRole::Button,
2144 LayoutNodeKind::Layout => layout_box
2145 .node_data
2146 .modifier_slices()
2147 .text_content()
2148 .map(|text| SemanticsRole::Text {
2149 value: text.to_string(),
2150 })
2151 .unwrap_or(SemanticsRole::Layout),
2152 }
2153}
2154
2155fn build_semantics_node_from_layout_box(layout_box: &LayoutBox) -> SemanticsNode {
2156 let children = layout_box
2157 .children
2158 .iter()
2159 .map(build_semantics_node_from_layout_box)
2160 .collect();
2161
2162 semantics_node_from_parts(
2163 layout_box.node_id,
2164 semantics_role_from_layout_box(layout_box),
2165 collect_semantics_from_modifier(&layout_box.node_data.modifier),
2166 children,
2167 )
2168}
2169
2170fn layout_kind_from_metadata(_node_id: NodeId, info: &RuntimeNodeMetadata) -> LayoutNodeKind {
2171 match &info.role {
2172 SemanticsRole::Layout => LayoutNodeKind::Layout,
2173 SemanticsRole::Subcompose => LayoutNodeKind::Subcompose,
2174 SemanticsRole::Text { .. } => {
2175 LayoutNodeKind::Layout
2179 }
2180 SemanticsRole::Spacer => LayoutNodeKind::Spacer,
2181 SemanticsRole::Button => {
2182 let handler = info
2183 .button_handler
2184 .as_ref()
2185 .cloned()
2186 .unwrap_or_else(|| Rc::new(RefCell::new(|| {})));
2187 LayoutNodeKind::Button { on_click: handler }
2188 }
2189 SemanticsRole::Unknown => LayoutNodeKind::Unknown,
2190 }
2191}
2192
2193fn subtract_padding(constraints: Constraints, padding: EdgeInsets) -> Constraints {
2194 let horizontal = padding.horizontal_sum();
2195 let vertical = padding.vertical_sum();
2196 let min_width = (constraints.min_width - horizontal).max(0.0);
2197 let mut max_width = constraints.max_width;
2198 if max_width.is_finite() {
2199 max_width = (max_width - horizontal).max(0.0);
2200 }
2201 let min_height = (constraints.min_height - vertical).max(0.0);
2202 let mut max_height = constraints.max_height;
2203 if max_height.is_finite() {
2204 max_height = (max_height - vertical).max(0.0);
2205 }
2206 normalize_constraints(Constraints {
2207 min_width,
2208 max_width,
2209 min_height,
2210 max_height,
2211 })
2212}
2213
2214#[cfg(test)]
2215pub(crate) fn align_horizontal(alignment: HorizontalAlignment, available: f32, child: f32) -> f32 {
2216 match alignment {
2217 HorizontalAlignment::Start => 0.0,
2218 HorizontalAlignment::CenterHorizontally => ((available - child) / 2.0).max(0.0),
2219 HorizontalAlignment::End => (available - child).max(0.0),
2220 }
2221}
2222
2223#[cfg(test)]
2224pub(crate) fn align_vertical(alignment: VerticalAlignment, available: f32, child: f32) -> f32 {
2225 match alignment {
2226 VerticalAlignment::Top => 0.0,
2227 VerticalAlignment::CenterVertically => ((available - child) / 2.0).max(0.0),
2228 VerticalAlignment::Bottom => (available - child).max(0.0),
2229 }
2230}
2231
2232fn resolve_dimension(
2233 base: f32,
2234 explicit: DimensionConstraint,
2235 min_override: Option<f32>,
2236 max_override: Option<f32>,
2237 min_limit: f32,
2238 max_limit: f32,
2239) -> f32 {
2240 let mut min_bound = min_limit;
2241 if let Some(min_value) = min_override {
2242 min_bound = min_bound.max(min_value);
2243 }
2244
2245 let mut max_bound = if max_limit.is_finite() {
2246 max_limit
2247 } else {
2248 max_override.unwrap_or(max_limit)
2249 };
2250 if let Some(max_value) = max_override {
2251 if max_bound.is_finite() {
2252 max_bound = max_bound.min(max_value);
2253 } else {
2254 max_bound = max_value;
2255 }
2256 }
2257 if max_bound < min_bound {
2258 max_bound = min_bound;
2259 }
2260
2261 let mut size = match explicit {
2262 DimensionConstraint::Points(points) => points,
2263 DimensionConstraint::Fraction(fraction) => {
2264 if max_limit.is_finite() {
2265 max_limit * fraction.clamp(0.0, 1.0)
2266 } else {
2267 base
2268 }
2269 }
2270 DimensionConstraint::Unspecified => base,
2271 DimensionConstraint::Intrinsic(_) => base,
2274 };
2275
2276 size = clamp_dimension(size, min_bound, max_bound);
2277 size = clamp_dimension(size, min_limit, max_limit);
2278 size.max(0.0)
2279}
2280
2281fn clamp_dimension(value: f32, min: f32, max: f32) -> f32 {
2282 let mut result = value.max(min);
2283 if max.is_finite() {
2284 result = result.min(max);
2285 }
2286 result
2287}
2288
2289fn normalize_constraints(mut constraints: Constraints) -> Constraints {
2290 if constraints.max_width < constraints.min_width {
2291 constraints.max_width = constraints.min_width;
2292 }
2293 if constraints.max_height < constraints.min_height {
2294 constraints.max_height = constraints.min_height;
2295 }
2296 constraints
2297}
2298
2299#[cfg(test)]
2300#[path = "tests/layout_tests.rs"]
2301mod tests;