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 mem::size_of,
12 rc::Rc,
13 sync::atomic::{AtomicU64, Ordering},
14};
15
16use cranpose_core::{
17 Applier, ApplierHost, Composer, ConcreteApplierHost, MemoryApplier, Node, NodeError, NodeId,
18 Phase, RuntimeHandle, SlotTable, SlotsHost, SnapshotStateObserver,
19};
20
21use self::coordinator::NodeCoordinator;
22use self::core::Measurable;
23use self::core::Placeable;
24#[cfg(test)]
25use self::core::{HorizontalAlignment, VerticalAlignment};
26use crate::modifier::{
27 collect_semantics_from_modifier, DimensionConstraint, EdgeInsets, Modifier, ModifierNodeSlices,
28 ModifierNodeSlicesDebugStats, Point, Rect as GeometryRect, ResolvedModifiers, Size,
29};
30
31use crate::subcompose_layout::SubcomposeLayoutNode;
32use crate::widgets::nodes::{IntrinsicKind, LayoutNode, LayoutNodeCacheHandles};
33use cranpose_foundation::{
34 InvalidationKind, ModifierNodeContext, NodeCapabilities, SemanticsConfiguration,
35};
36use cranpose_ui_layout::{Constraints, MeasurePolicy, MeasureResult};
37
38#[derive(Default)]
43pub(crate) struct LayoutNodeContext {
44 invalidations: Vec<InvalidationKind>,
45 update_requested: bool,
46 active_capabilities: Vec<NodeCapabilities>,
47}
48
49impl LayoutNodeContext {
50 pub(crate) fn new() -> Self {
51 Self::default()
52 }
53
54 pub(crate) fn take_invalidations(&mut self) -> Vec<InvalidationKind> {
55 std::mem::take(&mut self.invalidations)
56 }
57}
58
59impl ModifierNodeContext for LayoutNodeContext {
60 fn invalidate(&mut self, kind: InvalidationKind) {
61 if !self.invalidations.contains(&kind) {
62 self.invalidations.push(kind);
63 }
64 }
65
66 fn request_update(&mut self) {
67 self.update_requested = true;
68 }
69
70 fn push_active_capabilities(&mut self, capabilities: NodeCapabilities) {
71 self.active_capabilities.push(capabilities);
72 }
73
74 fn pop_active_capabilities(&mut self) {
75 self.active_capabilities.pop();
76 }
77}
78
79static NEXT_CACHE_EPOCH: AtomicU64 = AtomicU64::new(1);
80
81#[doc(hidden)]
104pub fn invalidate_all_layout_caches() {
105 NEXT_CACHE_EPOCH.fetch_add(1, Ordering::Relaxed);
106}
107
108struct ApplierSlotGuard<'a> {
119 target: &'a mut MemoryApplier,
121 host: Rc<ConcreteApplierHost<MemoryApplier>>,
123 slots: Rc<RefCell<SlotTable>>,
126}
127
128impl<'a> ApplierSlotGuard<'a> {
129 fn new(target: &'a mut MemoryApplier) -> Self {
133 let original_applier = std::mem::replace(target, MemoryApplier::new());
135 let host = Rc::new(ConcreteApplierHost::new(original_applier));
136
137 let slots = {
139 let mut applier_ref = host.borrow_typed();
140 std::mem::take(applier_ref.slots())
141 };
142 let slots = Rc::new(RefCell::new(slots));
143
144 Self {
145 target,
146 host,
147 slots,
148 }
149 }
150
151 fn host(&self) -> Rc<ConcreteApplierHost<MemoryApplier>> {
153 Rc::clone(&self.host)
154 }
155
156 fn slots_handle(&self) -> Rc<RefCell<SlotTable>> {
159 Rc::clone(&self.slots)
160 }
161}
162
163impl Drop for ApplierSlotGuard<'_> {
164 fn drop(&mut self) {
165 {
169 let mut applier_ref = self.host.borrow_typed();
170 *applier_ref.slots() = std::mem::take(&mut *self.slots.borrow_mut());
171 }
172
173 {
175 let mut applier_ref = self.host.borrow_typed();
176 let original_applier = std::mem::take(&mut *applier_ref);
177 let _ = std::mem::replace(self.target, original_applier);
178 }
179 }
181}
182
183struct ModifierChainMeasurement {
185 result: MeasureResult,
186 content_offset: Point,
188 offset: Point,
190}
191
192type LayoutModifierNodeData = (
193 usize,
194 Rc<RefCell<Box<dyn cranpose_foundation::ModifierNode>>>,
195);
196
197struct ScratchVecPool<T> {
198 available: Vec<Vec<T>>,
199}
200
201impl<T> ScratchVecPool<T> {
202 fn acquire(&mut self) -> Vec<T> {
203 self.available.pop().unwrap_or_default()
204 }
205
206 fn release(&mut self, mut values: Vec<T>) {
207 values.clear();
208 self.available.push(values);
209 }
210
211 #[cfg(test)]
212 fn available_count(&self) -> usize {
213 self.available.len()
214 }
215}
216
217impl<T> Default for ScratchVecPool<T> {
218 fn default() -> Self {
219 Self {
220 available: Vec::new(),
221 }
222 }
223}
224
225#[derive(Clone, Debug, PartialEq, Eq)]
227pub struct SemanticsCallback {
228 node_id: NodeId,
229}
230
231impl SemanticsCallback {
232 pub fn new(node_id: NodeId) -> Self {
233 Self { node_id }
234 }
235
236 pub fn node_id(&self) -> NodeId {
237 self.node_id
238 }
239}
240
241#[derive(Clone, Debug, PartialEq, Eq)]
243pub enum SemanticsAction {
244 Click { handler: SemanticsCallback },
245}
246
247#[derive(Clone, Debug, PartialEq, Eq)]
250pub enum SemanticsRole {
251 Layout,
253 Subcompose,
255 Text { value: String },
257 Spacer,
259 Button,
261 Unknown,
263}
264
265#[derive(Clone, Debug, PartialEq, Eq)]
267pub struct SemanticsNode {
268 pub node_id: NodeId,
269 pub role: SemanticsRole,
270 pub actions: Vec<SemanticsAction>,
271 pub children: Vec<SemanticsNode>,
272 pub description: Option<String>,
273}
274
275impl SemanticsNode {
276 fn new(
277 node_id: NodeId,
278 role: SemanticsRole,
279 actions: Vec<SemanticsAction>,
280 children: Vec<SemanticsNode>,
281 description: Option<String>,
282 ) -> Self {
283 Self {
284 node_id,
285 role,
286 actions,
287 children,
288 description,
289 }
290 }
291}
292
293#[derive(Clone, Debug, PartialEq, Eq)]
295pub struct SemanticsTree {
296 root: SemanticsNode,
297}
298
299impl SemanticsTree {
300 fn new(root: SemanticsNode) -> Self {
301 Self { root }
302 }
303
304 pub fn root(&self) -> &SemanticsNode {
305 &self.root
306 }
307}
308
309#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
310pub struct LayoutAllocationDebugStats {
311 pub layout_box_count: usize,
312 pub layout_box_child_count: usize,
313 pub layout_box_child_capacity: usize,
314 pub layout_box_heap_bytes: usize,
315 pub modifier_slice_count: usize,
316 pub modifier_slice_heap_bytes: usize,
317 pub modifier_draw_command_count: usize,
318 pub modifier_draw_command_capacity: usize,
319 pub modifier_pointer_input_count: usize,
320 pub modifier_pointer_input_capacity: usize,
321 pub modifier_click_handler_count: usize,
322 pub modifier_click_handler_capacity: usize,
323 pub modifier_text_content_count: usize,
324 pub modifier_text_style_count: usize,
325 pub modifier_text_layout_options_count: usize,
326 pub modifier_prepared_text_layout_count: usize,
327 pub modifier_graphics_layer_count: usize,
328 pub modifier_graphics_layer_resolver_count: usize,
329 pub semantics_node_count: usize,
330 pub semantics_action_count: usize,
331 pub semantics_action_capacity: usize,
332 pub semantics_child_count: usize,
333 pub semantics_child_capacity: usize,
334 pub semantics_description_count: usize,
335 pub semantics_description_bytes: usize,
336 pub semantics_text_role_bytes: usize,
337 pub semantics_heap_bytes: usize,
338}
339
340impl LayoutAllocationDebugStats {
341 fn add_modifier_slice(&mut self, stats: ModifierNodeSlicesDebugStats) {
342 self.modifier_slice_count += 1;
343 self.modifier_slice_heap_bytes += stats.heap_bytes;
344 self.modifier_draw_command_count += stats.draw_command_count;
345 self.modifier_draw_command_capacity += stats.draw_command_capacity;
346 self.modifier_pointer_input_count += stats.pointer_input_count;
347 self.modifier_pointer_input_capacity += stats.pointer_input_capacity;
348 self.modifier_click_handler_count += stats.click_handler_count;
349 self.modifier_click_handler_capacity += stats.click_handler_capacity;
350 self.modifier_text_content_count += usize::from(stats.has_text_content);
351 self.modifier_text_style_count += usize::from(stats.has_text_style);
352 self.modifier_text_layout_options_count += usize::from(stats.has_text_layout_options);
353 self.modifier_prepared_text_layout_count += usize::from(stats.has_prepared_text_layout);
354 self.modifier_graphics_layer_count += usize::from(stats.has_graphics_layer);
355 self.modifier_graphics_layer_resolver_count +=
356 usize::from(stats.has_graphics_layer_resolver);
357 }
358}
359
360#[derive(Debug, Clone)]
362pub struct LayoutTree {
363 root: LayoutBox,
364}
365
366impl LayoutTree {
367 pub fn new(root: LayoutBox) -> Self {
368 Self { root }
369 }
370
371 pub fn root(&self) -> &LayoutBox {
372 &self.root
373 }
374
375 pub fn root_mut(&mut self) -> &mut LayoutBox {
376 &mut self.root
377 }
378
379 pub fn into_root(self) -> LayoutBox {
380 self.root
381 }
382
383 pub fn debug_allocation_stats(&self) -> LayoutAllocationDebugStats {
384 let mut stats = LayoutAllocationDebugStats::default();
385 record_layout_box_allocation_stats(&self.root, &mut stats);
386 stats
387 }
388}
389
390#[derive(Debug, Clone)]
392pub struct LayoutBox {
393 pub node_id: NodeId,
394 pub rect: GeometryRect,
395 pub content_offset: Point,
397 pub node_data: LayoutNodeData,
398 pub children: Vec<LayoutBox>,
399}
400
401impl LayoutBox {
402 pub fn new(
403 node_id: NodeId,
404 rect: GeometryRect,
405 content_offset: Point,
406 node_data: LayoutNodeData,
407 children: Vec<LayoutBox>,
408 ) -> Self {
409 Self {
410 node_id,
411 rect,
412 content_offset,
413 node_data,
414 children,
415 }
416 }
417}
418
419#[derive(Debug, Clone)]
421pub struct LayoutNodeData {
422 pub modifier: Modifier,
423 pub resolved_modifiers: ResolvedModifiers,
424 pub modifier_slices: Rc<ModifierNodeSlices>,
425 pub kind: LayoutNodeKind,
426}
427
428impl LayoutNodeData {
429 pub fn new(
430 modifier: Modifier,
431 resolved_modifiers: ResolvedModifiers,
432 modifier_slices: Rc<ModifierNodeSlices>,
433 kind: LayoutNodeKind,
434 ) -> Self {
435 Self {
436 modifier,
437 resolved_modifiers,
438 modifier_slices,
439 kind,
440 }
441 }
442
443 pub fn resolved_modifiers(&self) -> ResolvedModifiers {
444 self.resolved_modifiers
445 }
446
447 pub fn modifier_slices(&self) -> &ModifierNodeSlices {
448 &self.modifier_slices
449 }
450}
451
452#[derive(Clone)]
459pub enum LayoutNodeKind {
460 Layout,
461 Subcompose,
462 Spacer,
463 Button { on_click: Rc<RefCell<dyn FnMut()>> },
464 Unknown,
465}
466
467impl fmt::Debug for LayoutNodeKind {
468 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
469 match self {
470 LayoutNodeKind::Layout => f.write_str("Layout"),
471 LayoutNodeKind::Subcompose => f.write_str("Subcompose"),
472 LayoutNodeKind::Spacer => f.write_str("Spacer"),
473 LayoutNodeKind::Button { .. } => f.write_str("Button"),
474 LayoutNodeKind::Unknown => f.write_str("Unknown"),
475 }
476 }
477}
478
479pub trait LayoutEngine {
481 fn compute_layout(&mut self, root: NodeId, max_size: Size) -> Result<LayoutTree, NodeError>;
482}
483
484impl LayoutEngine for MemoryApplier {
485 fn compute_layout(&mut self, root: NodeId, max_size: Size) -> Result<LayoutTree, NodeError> {
486 let measurements = measure_layout(self, root, max_size)?;
487 Ok(measurements.into_layout_tree())
488 }
489}
490
491#[derive(Debug, Clone)]
493pub struct LayoutMeasurements {
494 root: Rc<MeasuredNode>,
495 semantics: Option<SemanticsTree>,
496 layout_tree: Option<LayoutTree>,
497}
498
499impl LayoutMeasurements {
500 fn new(
501 root: Rc<MeasuredNode>,
502 semantics: Option<SemanticsTree>,
503 layout_tree: Option<LayoutTree>,
504 ) -> Self {
505 Self {
506 root,
507 semantics,
508 layout_tree,
509 }
510 }
511
512 pub fn root_size(&self) -> Size {
514 self.root.size
515 }
516
517 pub fn semantics_tree(&self) -> Option<&SemanticsTree> {
518 self.semantics.as_ref()
519 }
520
521 pub fn debug_allocation_stats(&self) -> LayoutAllocationDebugStats {
522 let mut stats = self
523 .layout_tree
524 .as_ref()
525 .map(LayoutTree::debug_allocation_stats)
526 .unwrap_or_default();
527 if let Some(semantics) = &self.semantics {
528 record_semantics_allocation_stats(semantics.root(), &mut stats);
529 }
530 stats
531 }
532
533 pub fn into_layout_tree(self) -> LayoutTree {
535 self.layout_tree
536 .expect("layout tree was not built for these measurements")
537 }
538
539 pub fn layout_tree(&self) -> LayoutTree {
541 self.layout_tree
542 .clone()
543 .expect("layout tree was not built for these measurements")
544 }
545}
546
547pub fn build_semantics_tree_from_layout_tree(layout_tree: &LayoutTree) -> SemanticsTree {
552 SemanticsTree::new(build_semantics_node_from_layout_box(layout_tree.root()))
553}
554
555pub fn build_layout_tree_from_applier(
561 applier: &mut MemoryApplier,
562 root: NodeId,
563) -> Result<Option<LayoutTree>, NodeError> {
564 fn snapshot(
565 applier: &mut MemoryApplier,
566 node_id: NodeId,
567 ) -> Result<Option<(crate::widgets::nodes::layout_node::LayoutState, Vec<NodeId>)>, NodeError>
568 {
569 match applier.with_node::<LayoutNode, _>(node_id, |node| {
570 (node.layout_state(), node.children.clone())
571 }) {
572 Ok(snapshot) => return Ok(Some(snapshot)),
573 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {}
574 Err(err) => return Err(err),
575 }
576
577 match applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
578 (node.layout_state(), node.active_children())
579 }) {
580 Ok(snapshot) => Ok(Some(snapshot)),
581 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => Ok(None),
582 Err(err) => Err(err),
583 }
584 }
585
586 fn place(
587 applier: &mut MemoryApplier,
588 node_id: NodeId,
589 parent_content_origin: Point,
590 ) -> Result<Option<LayoutBox>, NodeError> {
591 let Some((state, child_ids)) = snapshot(applier, node_id)? else {
592 return Ok(None);
593 };
594 if !state.is_placed {
595 return Ok(None);
596 }
597
598 let top_left = Point {
599 x: parent_content_origin.x + state.position.x,
600 y: parent_content_origin.y + state.position.y,
601 };
602 let rect = GeometryRect {
603 x: top_left.x,
604 y: top_left.y,
605 width: state.size.width,
606 height: state.size.height,
607 };
608 let info = runtime_metadata_for(applier, node_id)?;
609 let kind = layout_kind_from_metadata(node_id, &info);
610 let RuntimeNodeMetadata {
611 modifier,
612 resolved_modifiers,
613 modifier_slices,
614 ..
615 } = info;
616 let data = LayoutNodeData::new(modifier, resolved_modifiers, modifier_slices, kind);
617 let child_origin = Point {
618 x: top_left.x + state.content_offset.x,
619 y: top_left.y + state.content_offset.y,
620 };
621 let mut children = Vec::with_capacity(child_ids.len());
622 for child_id in child_ids {
623 if let Some(child) = place(applier, child_id, child_origin)? {
624 children.push(child);
625 }
626 }
627
628 Ok(Some(LayoutBox::new(
629 node_id,
630 rect,
631 state.content_offset,
632 data,
633 children,
634 )))
635 }
636
637 place(applier, root, Point::default()).map(|root| root.map(LayoutTree::new))
638}
639
640pub fn build_semantics_tree_from_applier(
646 applier: &mut MemoryApplier,
647 root: NodeId,
648) -> Result<Option<SemanticsTree>, NodeError> {
649 fn node(
650 applier: &mut MemoryApplier,
651 node_id: NodeId,
652 ) -> Result<Option<SemanticsNode>, NodeError> {
653 match applier.with_node::<LayoutNode, _>(node_id, |layout| {
654 let state = layout.layout_state();
655 if !state.is_placed {
656 return None;
657 }
658 let role = role_from_modifier_slices(&layout.modifier_slices_snapshot());
659 let config = layout.semantics_configuration();
660 let children = layout.children.clone();
661 layout.clear_needs_semantics();
662 Some((role, config, children))
663 }) {
664 Ok(Some((role, config, child_ids))) => {
665 let mut children = Vec::with_capacity(child_ids.len());
666 for child_id in child_ids {
667 if let Some(child) = node(applier, child_id)? {
668 children.push(child);
669 }
670 }
671 return Ok(Some(semantics_node_from_parts(
672 node_id, role, config, children,
673 )));
674 }
675 Ok(None) => return Ok(None),
676 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {}
677 Err(err) => return Err(err),
678 }
679
680 match applier.with_node::<SubcomposeLayoutNode, _>(node_id, |subcompose| {
681 let state = subcompose.layout_state();
682 if !state.is_placed {
683 return None;
684 }
685 let config = collect_semantics_from_modifier(&subcompose.modifier());
686 let children = subcompose.active_children();
687 subcompose.clear_needs_semantics();
688 Some((config, children))
689 }) {
690 Ok(Some((config, child_ids))) => {
691 let mut children = Vec::with_capacity(child_ids.len());
692 for child_id in child_ids {
693 if let Some(child) = node(applier, child_id)? {
694 children.push(child);
695 }
696 }
697 Ok(Some(semantics_node_from_parts(
698 node_id,
699 SemanticsRole::Subcompose,
700 config,
701 children,
702 )))
703 }
704 Ok(None) | Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {
705 Ok(None)
706 }
707 Err(err) => Err(err),
708 }
709 }
710
711 node(applier, root).map(|root| root.map(SemanticsTree::new))
712}
713
714#[derive(Clone, Copy, Debug, PartialEq, Eq)]
715pub struct MeasureLayoutOptions {
716 pub collect_semantics: bool,
717 pub build_layout_tree: bool,
718}
719
720impl Default for MeasureLayoutOptions {
721 fn default() -> Self {
722 Self {
723 collect_semantics: true,
724 build_layout_tree: true,
725 }
726 }
727}
728
729pub fn tree_needs_layout(applier: &mut dyn Applier, root: NodeId) -> Result<bool, NodeError> {
737 Ok(applier.get_mut(root)?.needs_layout())
738}
739
740pub fn tree_needs_semantics(applier: &mut dyn Applier, root: NodeId) -> Result<bool, NodeError> {
746 Ok(applier.get_mut(root)?.needs_semantics())
747}
748
749#[cfg(test)]
751pub(crate) fn bubble_layout_dirty(applier: &mut MemoryApplier, node_id: NodeId) {
752 cranpose_core::bubble_layout_dirty(applier as &mut dyn Applier, node_id);
753}
754
755pub fn measure_layout(
757 applier: &mut MemoryApplier,
758 root: NodeId,
759 max_size: Size,
760) -> Result<LayoutMeasurements, NodeError> {
761 measure_layout_with_options(applier, root, max_size, MeasureLayoutOptions::default())
762}
763
764pub fn measure_layout_with_options(
765 applier: &mut MemoryApplier,
766 root: NodeId,
767 max_size: Size,
768 options: MeasureLayoutOptions,
769) -> Result<LayoutMeasurements, NodeError> {
770 process_pending_layout_repasses(applier, root)?;
771
772 let constraints = Constraints {
773 min_width: 0.0,
774 max_width: max_size.width,
775 min_height: 0.0,
776 max_height: max_size.height,
777 };
778
779 let (needs_remeasure, _needs_semantics, cached_epoch) = match applier
790 .with_node::<LayoutNode, _>(root, |node| {
791 (
792 node.needs_measure(), node.needs_semantics(),
794 node.cache_handles().epoch(),
795 )
796 }) {
797 Ok(tuple) => tuple,
798 Err(NodeError::TypeMismatch { .. }) => {
799 let node = applier.get_mut(root)?;
800 let measure_dirty = node.needs_measure();
804 let semantics_dirty = node.needs_semantics();
805 (measure_dirty, semantics_dirty, 0)
806 }
807 Err(err) => return Err(err),
808 };
809
810 let epoch = if needs_remeasure {
811 NEXT_CACHE_EPOCH.fetch_add(1, Ordering::Relaxed)
812 } else if cached_epoch != 0 {
813 cached_epoch
814 } else {
815 NEXT_CACHE_EPOCH.load(Ordering::Relaxed)
817 };
818
819 let guard = ApplierSlotGuard::new(applier);
827 let applier_host = guard.host();
828 let slots_handle = guard.slots_handle();
829
830 let mut builder =
833 LayoutBuilder::new_with_epoch(Rc::clone(&applier_host), epoch, Rc::clone(&slots_handle));
834
835 let measured = builder.measure_node(root, normalize_constraints(constraints))?;
840
841 if let Ok(mut applier) = applier_host.try_borrow_typed() {
845 if applier
846 .with_node::<LayoutNode, _>(root, |node| {
847 node.set_position(Point::default());
848 })
849 .is_err()
850 {
851 let _ = applier.with_node::<SubcomposeLayoutNode, _>(root, |node| {
852 node.set_position(Point::default());
853 });
854 }
855 }
856
857 let (layout_tree, semantics) = {
858 let mut applier_ref = applier_host.borrow_typed();
859 let layout_tree = if options.build_layout_tree {
860 Some(build_layout_tree(&mut applier_ref, &measured)?)
861 } else {
862 None
863 };
864 let semantics = if options.collect_semantics {
865 let semantics_tree = if let Some(layout_tree) = layout_tree.as_ref() {
866 clear_semantics_dirty_flags(&mut applier_ref, &measured)?;
867 build_semantics_tree_from_layout_tree(layout_tree)
868 } else {
869 build_semantics_tree_from_live_nodes(&mut applier_ref, &measured)?
870 };
871 Some(semantics_tree)
872 } else {
873 None
874 };
875 (layout_tree, semantics)
876 };
877
878 drop(builder);
881
882 Ok(LayoutMeasurements::new(measured, semantics, layout_tree))
886}
887
888fn process_pending_layout_repasses(
889 applier: &mut MemoryApplier,
890 root: NodeId,
891) -> Result<(), NodeError> {
892 for node_id in crate::render_state::take_modifier_slice_repass_nodes() {
893 if let Ok(node) = applier.get_mut(node_id) {
894 let any = node.as_any_mut();
895 if let Some(layout) = any.downcast_mut::<crate::widgets::nodes::LayoutNode>() {
896 layout.mark_modifier_slices_dirty();
897 } else if let Some(subcompose) =
898 any.downcast_mut::<crate::subcompose_layout::SubcomposeLayoutNode>()
899 {
900 subcompose.mark_modifier_slices_dirty();
901 }
902 }
903 }
904 let repass_nodes = crate::take_layout_repass_nodes();
905 if repass_nodes.is_empty() {
906 return Ok(());
907 }
908 for node_id in repass_nodes {
909 cranpose_core::bubble_layout_dirty(applier as &mut dyn Applier, node_id);
910 }
911 applier.get_mut(root)?.mark_needs_layout();
912 Ok(())
913}
914
915struct LayoutBuilder {
916 state: Rc<RefCell<LayoutBuilderState>>,
917}
918
919impl LayoutBuilder {
920 fn new_with_epoch(
921 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
922 epoch: u64,
923 slots: Rc<RefCell<SlotTable>>,
924 ) -> Self {
925 Self {
926 state: Rc::new(RefCell::new(LayoutBuilderState::new_with_epoch(
927 applier, epoch, slots,
928 ))),
929 }
930 }
931
932 fn measure_node(
933 &mut self,
934 node_id: NodeId,
935 constraints: Constraints,
936 ) -> Result<Rc<MeasuredNode>, NodeError> {
937 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
938 }
939
940 fn set_runtime_handle(&mut self, handle: Option<RuntimeHandle>) {
941 self.state.borrow_mut().runtime_handle = handle;
942 }
943}
944
945struct LayoutBuilderState {
946 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
947 runtime_handle: Option<RuntimeHandle>,
948 slots: Rc<RefCell<SlotTable>>,
951 cache_epoch: u64,
952 tmp_measurables: ScratchVecPool<Box<dyn Measurable>>,
953 tmp_records: ScratchVecPool<(NodeId, ChildRecord)>,
954 tmp_child_ids: ScratchVecPool<NodeId>,
955 tmp_layout_node_data: ScratchVecPool<LayoutModifierNodeData>,
956}
957
958impl LayoutBuilderState {
959 fn new_with_epoch(
960 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
961 epoch: u64,
962 slots: Rc<RefCell<SlotTable>>,
963 ) -> Self {
964 let runtime_handle = applier.borrow_typed().runtime_handle();
965
966 Self {
967 applier,
968 runtime_handle,
969 slots,
970 cache_epoch: epoch,
971 tmp_measurables: ScratchVecPool::default(),
972 tmp_records: ScratchVecPool::default(),
973 tmp_child_ids: ScratchVecPool::default(),
974 tmp_layout_node_data: ScratchVecPool::default(),
975 }
976 }
977
978 fn try_with_applier_result<R>(
979 state_rc: &Rc<RefCell<Self>>,
980 f: impl FnOnce(&mut MemoryApplier) -> Result<R, NodeError>,
981 ) -> Option<Result<R, NodeError>> {
982 let host = {
983 let state = state_rc.borrow();
984 Rc::clone(&state.applier)
985 };
986
987 let Ok(mut applier) = host.try_borrow_typed() else {
989 return None;
990 };
991
992 Some(f(&mut applier))
993 }
994
995 fn with_applier_result<R>(
996 state_rc: &Rc<RefCell<Self>>,
997 f: impl FnOnce(&mut MemoryApplier) -> Result<R, NodeError>,
998 ) -> Result<R, NodeError> {
999 Self::try_with_applier_result(state_rc, f).unwrap_or_else(|| {
1000 Err(NodeError::MissingContext {
1001 id: NodeId::default(),
1002 reason: "applier already borrowed",
1003 })
1004 })
1005 }
1006
1007 fn clear_node_placed(state_rc: &Rc<RefCell<Self>>, node_id: NodeId) {
1010 let host = {
1011 let state = state_rc.borrow();
1012 Rc::clone(&state.applier)
1013 };
1014 let Ok(mut applier) = host.try_borrow_typed() else {
1015 return;
1016 };
1017 if applier
1019 .with_node::<LayoutNode, _>(node_id, |node| {
1020 node.clear_placed();
1021 })
1022 .is_err()
1023 {
1024 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1025 node.clear_placed();
1026 });
1027 }
1028 }
1029
1030 fn measure_node(
1031 state_rc: Rc<RefCell<Self>>,
1032 node_id: NodeId,
1033 constraints: Constraints,
1034 ) -> Result<Rc<MeasuredNode>, NodeError> {
1035 Self::clear_node_placed(&state_rc, node_id);
1039
1040 if let Some(subcompose) =
1042 Self::try_measure_subcompose(Rc::clone(&state_rc), node_id, constraints)?
1043 {
1044 return Ok(subcompose);
1045 }
1046
1047 if let Some(result) = Self::try_with_applier_result(&state_rc, |applier| {
1049 match applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1050 LayoutNodeSnapshot::from_layout_node(layout_node)
1051 }) {
1052 Ok(snapshot) => Ok(Some(snapshot)),
1053 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => Ok(None),
1054 Err(err) => Err(err),
1055 }
1056 }) {
1057 if let Some(snapshot) = result? {
1059 return Self::measure_layout_node(
1060 Rc::clone(&state_rc),
1061 node_id,
1062 snapshot,
1063 constraints,
1064 );
1065 }
1066 }
1067 Ok(Rc::new(MeasuredNode::new(
1072 node_id,
1073 Size::default(),
1074 Point { x: 0.0, y: 0.0 },
1075 Point::default(), Vec::new(),
1077 )))
1078 }
1079
1080 fn try_measure_subcompose(
1081 state_rc: Rc<RefCell<Self>>,
1082 node_id: NodeId,
1083 constraints: Constraints,
1084 ) -> Result<Option<Rc<MeasuredNode>>, NodeError> {
1085 let applier_host = {
1086 let state = state_rc.borrow();
1087 Rc::clone(&state.applier)
1088 };
1089
1090 let (node_handle, resolved_modifiers) = {
1091 let Ok(mut applier) = applier_host.try_borrow_typed() else {
1093 return Ok(None);
1094 };
1095 let node = match applier.get_mut(node_id) {
1096 Ok(node) => node,
1097 Err(NodeError::Missing { .. }) => return Ok(None),
1098 Err(err) => return Err(err),
1099 };
1100 let any = node.as_any_mut();
1101 if let Some(subcompose) =
1102 any.downcast_mut::<crate::subcompose_layout::SubcomposeLayoutNode>()
1103 {
1104 let handle = subcompose.handle();
1105 let resolved_modifiers = handle.resolved_modifiers();
1106 (handle, resolved_modifiers)
1107 } else {
1108 return Ok(None);
1109 }
1110 };
1111
1112 let runtime_handle = {
1113 let mut state = state_rc.borrow_mut();
1114 if state.runtime_handle.is_none() {
1115 if let Ok(applier) = applier_host.try_borrow_typed() {
1117 state.runtime_handle = applier.runtime_handle();
1118 }
1119 }
1120 state
1121 .runtime_handle
1122 .clone()
1123 .ok_or(NodeError::MissingContext {
1124 id: node_id,
1125 reason: "runtime handle required for subcomposition",
1126 })?
1127 };
1128
1129 let props = resolved_modifiers.layout_properties();
1130 let padding = resolved_modifiers.padding();
1131 let offset = resolved_modifiers.offset();
1132 let mut inner_constraints = normalize_constraints(subtract_padding(constraints, padding));
1133
1134 if let DimensionConstraint::Points(width) = props.width() {
1135 let constrained_width = width - padding.horizontal_sum();
1136 inner_constraints.max_width = inner_constraints.max_width.min(constrained_width);
1137 inner_constraints.min_width = inner_constraints.min_width.min(constrained_width);
1138 }
1139 if let DimensionConstraint::Points(height) = props.height() {
1140 let constrained_height = height - padding.vertical_sum();
1141 inner_constraints.max_height = inner_constraints.max_height.min(constrained_height);
1142 inner_constraints.min_height = inner_constraints.min_height.min(constrained_height);
1143 }
1144
1145 let mut slots_guard = SlotsGuard::take(Rc::clone(&state_rc));
1146 let slots_host = slots_guard.host();
1147 let applier_host_dyn: Rc<dyn ApplierHost> = applier_host.clone();
1148 let observer = SnapshotStateObserver::new(|callback| callback());
1149 let composer = Composer::new(
1150 Rc::clone(&slots_host),
1151 applier_host_dyn,
1152 runtime_handle.clone(),
1153 observer,
1154 Some(node_id),
1155 );
1156 composer.enter_phase(Phase::Measure);
1157
1158 let state_rc_clone = Rc::clone(&state_rc);
1159 let measure_error = RefCell::new(None);
1160 let state_rc_for_subcompose = Rc::clone(&state_rc_clone);
1161 let error_for_subcompose = &measure_error;
1162 let measured_children: Rc<RefCell<HashMap<NodeId, Rc<MeasuredNode>>>> =
1163 Rc::new(RefCell::new(HashMap::default()));
1164 let measured_children_for_subcompose = Rc::clone(&measured_children);
1165
1166 let measure_result = node_handle.measure(
1167 &composer,
1168 node_id,
1169 inner_constraints,
1170 Box::new(
1171 move |child_id: NodeId, child_constraints: Constraints| -> Size {
1172 match Self::measure_node(
1173 Rc::clone(&state_rc_for_subcompose),
1174 child_id,
1175 child_constraints,
1176 ) {
1177 Ok(measured) => {
1178 measured_children_for_subcompose
1179 .borrow_mut()
1180 .insert(child_id, Rc::clone(&measured));
1181 measured.size
1182 }
1183 Err(err) => {
1184 let mut slot = error_for_subcompose.borrow_mut();
1185 if slot.is_none() {
1186 *slot = Some(err);
1187 }
1188 Size::default()
1189 }
1190 }
1191 },
1192 ),
1193 &measure_error,
1194 )?;
1195 drop(composer);
1196 slots_guard.restore(slots_host.into_table()?);
1197
1198 if let Some(err) = measure_error.borrow_mut().take() {
1199 return Err(err);
1200 }
1201
1202 let mut width = measure_result.size.width + padding.horizontal_sum();
1206 let mut height = measure_result.size.height + padding.vertical_sum();
1207
1208 width = resolve_dimension(
1209 width,
1210 props.width(),
1211 props.min_width(),
1212 props.max_width(),
1213 constraints.min_width,
1214 constraints.max_width,
1215 );
1216 height = resolve_dimension(
1217 height,
1218 props.height(),
1219 props.min_height(),
1220 props.max_height(),
1221 constraints.min_height,
1222 constraints.max_height,
1223 );
1224
1225 let mut children = Vec::with_capacity(measure_result.placements.len());
1226 let mut measured_children_by_id = measured_children.borrow_mut();
1227
1228 if let Ok(mut applier) = applier_host.try_borrow_typed() {
1230 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |parent_node| {
1231 parent_node.set_measured_size(Size { width, height });
1232 parent_node.clear_needs_measure();
1233 parent_node.clear_needs_layout();
1234 });
1235 }
1236
1237 for placement in measure_result.placements {
1238 let child = if let Some(measured) = measured_children_by_id.remove(&placement.node_id) {
1239 measured
1240 } else {
1241 Self::measure_node(Rc::clone(&state_rc), placement.node_id, inner_constraints)?
1247 };
1248 let position = Point {
1249 x: padding.left + placement.x,
1250 y: padding.top + placement.y,
1251 };
1252
1253 if let Ok(mut applier) = applier_host.try_borrow_typed() {
1257 let _ = applier.with_node::<LayoutNode, _>(placement.node_id, |node| {
1258 node.set_position(position);
1259 });
1260 }
1261
1262 children.push(MeasuredChild {
1263 node: child,
1264 offset: position,
1265 });
1266 }
1267
1268 node_handle.set_active_children(children.iter().map(|c| c.node.node_id));
1270
1271 Ok(Some(Rc::new(MeasuredNode::new(
1272 node_id,
1273 Size { width, height },
1274 offset,
1275 Point::default(), children,
1277 ))))
1278 }
1279 fn measure_through_modifier_chain(
1286 state_rc: &Rc<RefCell<Self>>,
1287 node_id: NodeId,
1288 measurables: &[Box<dyn Measurable>],
1289 measure_policy: &Rc<dyn MeasurePolicy>,
1290 constraints: Constraints,
1291 layout_node_data: &mut Vec<LayoutModifierNodeData>,
1292 ) -> ModifierChainMeasurement {
1293 use cranpose_foundation::NodeCapabilities;
1294
1295 layout_node_data.clear();
1297 let mut offset = Point::default();
1298
1299 {
1300 let state = state_rc.borrow();
1301 let mut applier = state.applier.borrow_typed();
1302
1303 let _ = applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1304 let chain_handle = layout_node.modifier_chain();
1305
1306 if !chain_handle.has_layout_nodes() {
1307 return;
1308 }
1309
1310 chain_handle.chain().for_each_forward_matching(
1312 NodeCapabilities::LAYOUT,
1313 |node_ref| {
1314 if let Some(index) = node_ref.entry_index() {
1315 if let Some(node_rc) = chain_handle.chain().get_node_rc(index) {
1317 layout_node_data.push((index, Rc::clone(&node_rc)));
1318 }
1319
1320 node_ref.with_node(|node| {
1324 if let Some(offset_node) =
1325 node.as_any()
1326 .downcast_ref::<crate::modifier_nodes::OffsetNode>()
1327 {
1328 let delta = offset_node.offset();
1329 offset.x += delta.x;
1330 offset.y += delta.y;
1331 }
1332 });
1333 }
1334 },
1335 );
1336 });
1337 }
1338
1339 if layout_node_data.is_empty() {
1342 let result = measure_policy.measure(measurables, constraints);
1343 let final_size = result.size;
1344 let placements = result.placements;
1345
1346 return ModifierChainMeasurement {
1347 result: MeasureResult {
1348 size: final_size,
1349 placements,
1350 },
1351 content_offset: Point::default(),
1352 offset,
1353 };
1354 }
1355
1356 let shared_context = Rc::new(RefCell::new(LayoutNodeContext::new()));
1361
1362 let policy_result = Rc::new(RefCell::new(None));
1364 let inner_coordinator: Box<dyn NodeCoordinator + '_> =
1365 Box::new(coordinator::InnerCoordinator::new(
1366 Rc::clone(measure_policy),
1367 measurables,
1368 Rc::clone(&policy_result),
1369 ));
1370
1371 let mut current_coordinator = inner_coordinator;
1373 while let Some((_, node_rc)) = layout_node_data.pop() {
1374 current_coordinator = Box::new(coordinator::LayoutModifierCoordinator::new(
1375 node_rc,
1376 current_coordinator,
1377 Rc::clone(&shared_context),
1378 ));
1379 }
1380
1381 let placeable = current_coordinator.measure(constraints);
1383 let final_size = Size {
1384 width: placeable.width(),
1385 height: placeable.height(),
1386 };
1387
1388 let content_offset = placeable.content_offset();
1390 let all_placement_offset = Point {
1391 x: content_offset.0,
1392 y: content_offset.1,
1393 };
1394
1395 let content_offset = Point {
1399 x: all_placement_offset.x - offset.x,
1400 y: all_placement_offset.y - offset.y,
1401 };
1402
1403 let placements = policy_result
1406 .borrow_mut()
1407 .take()
1408 .map(|result| result.placements)
1409 .unwrap_or_default();
1410
1411 let invalidations = shared_context.borrow_mut().take_invalidations();
1413 if !invalidations.is_empty() {
1414 Self::with_applier_result(state_rc, |applier| {
1416 applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1417 for kind in invalidations {
1418 match kind {
1419 InvalidationKind::Layout => layout_node.mark_needs_measure(),
1420 InvalidationKind::Draw => layout_node.mark_needs_redraw(),
1421 InvalidationKind::Semantics => layout_node.mark_needs_semantics(),
1422 InvalidationKind::PointerInput => layout_node.mark_needs_pointer_pass(),
1423 InvalidationKind::Focus => layout_node.mark_needs_focus_sync(),
1424 }
1425 }
1426 })
1427 })
1428 .ok();
1429 }
1430
1431 ModifierChainMeasurement {
1432 result: MeasureResult {
1433 size: final_size,
1434 placements,
1435 },
1436 content_offset,
1437 offset,
1438 }
1439 }
1440
1441 fn measure_layout_node(
1442 state_rc: Rc<RefCell<Self>>,
1443 node_id: NodeId,
1444 snapshot: LayoutNodeSnapshot,
1445 constraints: Constraints,
1446 ) -> Result<Rc<MeasuredNode>, NodeError> {
1447 let cache_epoch = {
1448 let state = state_rc.borrow();
1449 state.cache_epoch
1450 };
1451 let LayoutNodeSnapshot {
1452 measure_policy,
1453 cache,
1454 needs_layout,
1455 needs_measure,
1456 } = snapshot;
1457 cache.activate(cache_epoch);
1458
1459 if needs_measure {
1460 }
1462
1463 if !needs_measure && !needs_layout {
1467 if let Some(cached) = cache.get_measurement(constraints) {
1469 Self::with_applier_result(&state_rc, |applier| {
1471 applier.with_node::<LayoutNode, _>(node_id, |node| {
1472 node.clear_needs_measure();
1473 node.clear_needs_layout();
1474 })
1475 })
1476 .ok();
1477 return Ok(cached);
1478 }
1479 }
1480
1481 let (runtime_handle, applier_host) = {
1482 let state = state_rc.borrow();
1483 (state.runtime_handle.clone(), Rc::clone(&state.applier))
1484 };
1485
1486 let measure_handle = LayoutMeasureHandle::new(Rc::clone(&state_rc));
1487 let error = Rc::new(RefCell::new(None));
1488 let mut pools = VecPools::acquire(Rc::clone(&state_rc));
1489 let (measurables, records, child_ids, layout_node_data) = pools.parts();
1490
1491 applier_host
1492 .borrow_typed()
1493 .with_node::<LayoutNode, _>(node_id, |node| {
1494 child_ids.extend_from_slice(&node.children);
1495 })?;
1496
1497 for &child_id in child_ids.iter() {
1498 let measured = Rc::new(RefCell::new(None));
1499 let position = Rc::new(RefCell::new(None));
1500
1501 let data = {
1502 let mut applier = applier_host.borrow_typed();
1503 match applier.with_node::<LayoutNode, _>(child_id, |n| {
1504 (
1505 n.cache_handles(),
1506 n.layout_state_handle(),
1507 n.needs_layout(),
1508 n.needs_measure(),
1509 )
1510 }) {
1511 Ok((cache, state, needs_layout, needs_measure)) => {
1512 Some((cache, Some(state), needs_layout, needs_measure))
1513 }
1514 Err(NodeError::TypeMismatch { .. }) => {
1515 match applier.with_node::<SubcomposeLayoutNode, _>(child_id, |n| {
1516 (n.needs_layout(), n.needs_measure())
1517 }) {
1518 Ok((needs_layout, needs_measure)) => Some((
1519 LayoutNodeCacheHandles::default(),
1520 None,
1521 needs_layout,
1522 needs_measure,
1523 )),
1524 Err(NodeError::TypeMismatch { .. }) => None,
1525 Err(NodeError::Missing { .. }) => None,
1526 Err(err) => return Err(err),
1527 }
1528 }
1529 Err(NodeError::Missing { .. }) => None,
1530 Err(err) => return Err(err),
1531 }
1532 };
1533
1534 let Some((cache_handles, layout_state, needs_layout, needs_measure)) = data else {
1535 continue;
1536 };
1537
1538 cache_handles.activate(cache_epoch);
1539
1540 records.push((
1541 child_id,
1542 ChildRecord {
1543 measured: Rc::clone(&measured),
1544 last_position: Rc::clone(&position),
1545 },
1546 ));
1547 measurables.push(Box::new(LayoutChildMeasurable::new(
1548 Rc::clone(&applier_host),
1549 child_id,
1550 measured,
1551 position,
1552 Rc::clone(&error),
1553 runtime_handle.clone(),
1554 cache_handles,
1555 cache_epoch,
1556 needs_layout || needs_measure,
1557 Some(measure_handle.clone()),
1558 layout_state,
1559 )));
1560 }
1561
1562 let chain_constraints = constraints;
1563
1564 let modifier_chain_result = Self::measure_through_modifier_chain(
1565 &state_rc,
1566 node_id,
1567 measurables.as_slice(),
1568 &measure_policy,
1569 chain_constraints,
1570 layout_node_data,
1571 );
1572
1573 let (width, height, policy_result, content_offset, offset) = {
1575 let result = modifier_chain_result;
1576 if let Some(err) = error.borrow_mut().take() {
1579 return Err(err);
1580 }
1581
1582 (
1583 result.result.size.width,
1584 result.result.size.height,
1585 result.result,
1586 result.content_offset,
1587 result.offset,
1588 )
1589 };
1590
1591 let mut measured_children = Vec::with_capacity(records.len());
1592 for (child_id, record) in records.iter() {
1593 if let Some(measured) = record.measured.borrow_mut().take() {
1594 let base_position = policy_result
1595 .placements
1596 .iter()
1597 .find(|placement| placement.node_id == *child_id)
1598 .map(|placement| Point {
1599 x: placement.x,
1600 y: placement.y,
1601 })
1602 .or_else(|| record.last_position.borrow().as_ref().copied())
1603 .unwrap_or(Point { x: 0.0, y: 0.0 });
1604 let position = Point {
1606 x: content_offset.x + base_position.x,
1607 y: content_offset.y + base_position.y,
1608 };
1609 measured_children.push(MeasuredChild {
1610 node: measured,
1611 offset: position,
1612 });
1613 }
1614 }
1615
1616 let measured = Rc::new(MeasuredNode::new(
1617 node_id,
1618 Size { width, height },
1619 offset,
1620 content_offset,
1621 measured_children,
1622 ));
1623
1624 cache.store_measurement(constraints, Rc::clone(&measured));
1625
1626 Self::with_applier_result(&state_rc, |applier| {
1628 applier.with_node::<LayoutNode, _>(node_id, |node| {
1629 node.clear_needs_measure();
1630 node.clear_needs_layout();
1631 node.set_measured_size(Size { width, height });
1632 node.set_content_offset(content_offset);
1633 })
1634 })
1635 .ok();
1636
1637 Ok(measured)
1638 }
1639}
1640
1641struct LayoutNodeSnapshot {
1648 measure_policy: Rc<dyn MeasurePolicy>,
1649 cache: LayoutNodeCacheHandles,
1650 needs_layout: bool,
1651 needs_measure: bool,
1653}
1654
1655impl LayoutNodeSnapshot {
1656 fn from_layout_node(node: &LayoutNode) -> Self {
1657 Self {
1658 measure_policy: Rc::clone(&node.measure_policy),
1659 cache: node.cache_handles(),
1660 needs_layout: node.needs_layout(),
1661 needs_measure: node.needs_measure(),
1662 }
1663 }
1664}
1665
1666struct VecPools {
1668 state: Rc<RefCell<LayoutBuilderState>>,
1669 measurables: Option<Vec<Box<dyn Measurable>>>,
1670 records: Option<Vec<(NodeId, ChildRecord)>>,
1671 child_ids: Option<Vec<NodeId>>,
1672 layout_node_data: Option<Vec<LayoutModifierNodeData>>,
1673}
1674
1675impl VecPools {
1676 fn acquire(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1677 let (measurables, records, child_ids, layout_node_data) = {
1678 let mut state_mut = state.borrow_mut();
1679 (
1680 state_mut.tmp_measurables.acquire(),
1681 state_mut.tmp_records.acquire(),
1682 state_mut.tmp_child_ids.acquire(),
1683 state_mut.tmp_layout_node_data.acquire(),
1684 )
1685 };
1686 Self {
1687 state,
1688 measurables: Some(measurables),
1689 records: Some(records),
1690 child_ids: Some(child_ids),
1691 layout_node_data: Some(layout_node_data),
1692 }
1693 }
1694
1695 #[allow(clippy::type_complexity)] fn parts(
1697 &mut self,
1698 ) -> (
1699 &mut Vec<Box<dyn Measurable>>,
1700 &mut Vec<(NodeId, ChildRecord)>,
1701 &mut Vec<NodeId>,
1702 &mut Vec<LayoutModifierNodeData>,
1703 ) {
1704 let measurables = self
1705 .measurables
1706 .as_mut()
1707 .expect("measurables already returned");
1708 let records = self.records.as_mut().expect("records already returned");
1709 let child_ids = self.child_ids.as_mut().expect("child_ids already returned");
1710 let layout_node_data = self
1711 .layout_node_data
1712 .as_mut()
1713 .expect("layout_node_data already returned");
1714 (measurables, records, child_ids, layout_node_data)
1715 }
1716}
1717
1718impl Drop for VecPools {
1719 fn drop(&mut self) {
1720 let mut state = self.state.borrow_mut();
1721 if let Some(measurables) = self.measurables.take() {
1722 state.tmp_measurables.release(measurables);
1723 }
1724 if let Some(records) = self.records.take() {
1725 state.tmp_records.release(records);
1726 }
1727 if let Some(child_ids) = self.child_ids.take() {
1728 state.tmp_child_ids.release(child_ids);
1729 }
1730 if let Some(layout_node_data) = self.layout_node_data.take() {
1731 state.tmp_layout_node_data.release(layout_node_data);
1732 }
1733 }
1734}
1735
1736struct SlotsGuard {
1737 state: Rc<RefCell<LayoutBuilderState>>,
1738 slots: Option<SlotTable>,
1739}
1740
1741impl SlotsGuard {
1742 fn take(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1743 let slots = {
1744 let state_ref = state.borrow();
1745 let mut slots_ref = state_ref.slots.borrow_mut();
1746 std::mem::take(&mut *slots_ref)
1747 };
1748 Self {
1749 state,
1750 slots: Some(slots),
1751 }
1752 }
1753
1754 fn host(&mut self) -> Rc<SlotsHost> {
1755 let slots = self.slots.take().unwrap_or_default();
1756 Rc::new(SlotsHost::new(slots))
1757 }
1758
1759 fn restore(&mut self, slots: SlotTable) {
1760 debug_assert!(self.slots.is_none());
1761 self.slots = Some(slots);
1762 }
1763}
1764
1765impl Drop for SlotsGuard {
1766 fn drop(&mut self) {
1767 if let Some(slots) = self.slots.take() {
1768 let state_ref = self.state.borrow();
1769 *state_ref.slots.borrow_mut() = slots;
1770 }
1771 }
1772}
1773
1774#[derive(Clone)]
1775struct LayoutMeasureHandle {
1776 state: Rc<RefCell<LayoutBuilderState>>,
1777}
1778
1779impl LayoutMeasureHandle {
1780 fn new(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1781 Self { state }
1782 }
1783
1784 fn measure(
1785 &self,
1786 node_id: NodeId,
1787 constraints: Constraints,
1788 ) -> Result<Rc<MeasuredNode>, NodeError> {
1789 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
1790 }
1791}
1792
1793#[derive(Debug, Clone)]
1794pub(crate) struct MeasuredNode {
1795 node_id: NodeId,
1796 size: Size,
1797 offset: Point,
1799 content_offset: Point,
1801 children: Vec<MeasuredChild>,
1802}
1803
1804impl MeasuredNode {
1805 fn new(
1806 node_id: NodeId,
1807 size: Size,
1808 offset: Point,
1809 content_offset: Point,
1810 children: Vec<MeasuredChild>,
1811 ) -> Self {
1812 Self {
1813 node_id,
1814 size,
1815 offset,
1816 content_offset,
1817 children,
1818 }
1819 }
1820}
1821
1822#[derive(Debug, Clone)]
1823struct MeasuredChild {
1824 node: Rc<MeasuredNode>,
1825 offset: Point,
1826}
1827
1828struct ChildRecord {
1829 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1830 last_position: Rc<RefCell<Option<Point>>>,
1831}
1832
1833struct LayoutChildMeasurable {
1834 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1835 node_id: NodeId,
1836 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1837 last_position: Rc<RefCell<Option<Point>>>,
1838 error: Rc<RefCell<Option<NodeError>>>,
1839 runtime_handle: Option<RuntimeHandle>,
1840 cache: LayoutNodeCacheHandles,
1841 cache_epoch: u64,
1842 force_remeasure: Cell<bool>,
1843 measure_handle: Option<LayoutMeasureHandle>,
1844 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1845}
1846
1847impl LayoutChildMeasurable {
1848 #[allow(clippy::too_many_arguments)] fn new(
1850 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1851 node_id: NodeId,
1852 measured: Rc<RefCell<Option<Rc<MeasuredNode>>>>,
1853 last_position: Rc<RefCell<Option<Point>>>,
1854 error: Rc<RefCell<Option<NodeError>>>,
1855 runtime_handle: Option<RuntimeHandle>,
1856 cache: LayoutNodeCacheHandles,
1857 cache_epoch: u64,
1858 force_remeasure: bool,
1859 measure_handle: Option<LayoutMeasureHandle>,
1860 layout_state: Option<Rc<RefCell<crate::widgets::nodes::layout_node::LayoutState>>>,
1861 ) -> Self {
1862 cache.activate(cache_epoch);
1863 Self {
1864 applier,
1865 node_id,
1866 measured,
1867 last_position,
1868 error,
1869 runtime_handle,
1870 cache,
1871 cache_epoch,
1872 force_remeasure: Cell::new(force_remeasure),
1873 measure_handle,
1874 layout_state,
1875 }
1876 }
1877
1878 fn record_error(&self, err: NodeError) {
1879 let mut slot = self.error.borrow_mut();
1880 if slot.is_none() {
1881 *slot = Some(err);
1882 }
1883 }
1884
1885 fn perform_measure(&self, constraints: Constraints) -> Result<Rc<MeasuredNode>, NodeError> {
1886 if let Some(handle) = &self.measure_handle {
1887 handle.measure(self.node_id, constraints)
1888 } else {
1889 measure_node_with_host(
1890 Rc::clone(&self.applier),
1891 self.runtime_handle.clone(),
1892 self.node_id,
1893 constraints,
1894 self.cache_epoch,
1895 )
1896 }
1897 }
1898
1899 fn intrinsic_measure(&self, constraints: Constraints) -> Option<Rc<MeasuredNode>> {
1900 self.cache.activate(self.cache_epoch);
1901 if !self.force_remeasure.get() {
1902 if let Some(cached) = self.cache.get_measurement(constraints) {
1903 return Some(cached);
1904 }
1905 }
1906
1907 match self.perform_measure(constraints) {
1908 Ok(measured) => {
1909 self.force_remeasure.set(false);
1910 self.cache
1911 .store_measurement(constraints, Rc::clone(&measured));
1912 Some(measured)
1913 }
1914 Err(err) => {
1915 self.record_error(err);
1916 None
1917 }
1918 }
1919 }
1920}
1921
1922impl Measurable for LayoutChildMeasurable {
1923 fn measure(&self, constraints: Constraints) -> Placeable {
1924 self.cache.activate(self.cache_epoch);
1925 let measured_size;
1926 if !self.force_remeasure.get() {
1927 if let Some(cached) = self.cache.get_measurement(constraints) {
1928 measured_size = cached.size;
1929 *self.measured.borrow_mut() = Some(Rc::clone(&cached));
1930 } else {
1931 match self.perform_measure(constraints) {
1932 Ok(measured) => {
1933 self.force_remeasure.set(false);
1934 measured_size = measured.size;
1935 self.cache
1936 .store_measurement(constraints, Rc::clone(&measured));
1937 *self.measured.borrow_mut() = Some(measured);
1938 }
1939 Err(err) => {
1940 self.record_error(err);
1941 self.measured.borrow_mut().take();
1942 measured_size = Size {
1943 width: 0.0,
1944 height: 0.0,
1945 };
1946 }
1947 }
1948 }
1949 } else {
1950 match self.perform_measure(constraints) {
1951 Ok(measured) => {
1952 self.force_remeasure.set(false);
1953 measured_size = measured.size;
1954 self.cache
1955 .store_measurement(constraints, Rc::clone(&measured));
1956 *self.measured.borrow_mut() = Some(measured);
1957 }
1958 Err(err) => {
1959 self.record_error(err);
1960 self.measured.borrow_mut().take();
1961 measured_size = Size {
1962 width: 0.0,
1963 height: 0.0,
1964 };
1965 }
1966 }
1967 }
1968
1969 if let Some(state) = &self.layout_state {
1972 let mut state = state.borrow_mut();
1973 state.size = measured_size;
1974 state.measurement_constraints = constraints;
1975 } else if let Ok(mut applier) = self.applier.try_borrow_typed() {
1976 let _ = applier.with_node::<LayoutNode, _>(self.node_id, |node| {
1977 node.set_measured_size(measured_size);
1978 node.set_measurement_constraints(constraints);
1979 });
1980 }
1981
1982 let applier = Rc::clone(&self.applier);
1984 let node_id = self.node_id;
1985 let measured = Rc::clone(&self.measured);
1986 let last_position = Rc::clone(&self.last_position);
1987 let layout_state = self.layout_state.clone();
1988
1989 let place_fn = Rc::new(move |x: f32, y: f32| {
1990 let internal_offset = measured
1992 .borrow()
1993 .as_ref()
1994 .map(|m| m.offset)
1995 .unwrap_or_default();
1996
1997 let position = Point {
1998 x: x + internal_offset.x,
1999 y: y + internal_offset.y,
2000 };
2001 *last_position.borrow_mut() = Some(position);
2002
2003 if let Some(state) = &layout_state {
2005 let mut state = state.borrow_mut();
2006 state.position = position;
2007 state.is_placed = true;
2008 } else if let Ok(mut applier) = applier.try_borrow_typed() {
2009 if applier
2010 .with_node::<LayoutNode, _>(node_id, |node| {
2011 node.set_position(position);
2012 })
2013 .is_err()
2014 {
2015 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
2016 node.set_position(position);
2017 });
2018 }
2019 }
2020 });
2021
2022 Placeable::with_place_fn(
2023 measured_size.width,
2024 measured_size.height,
2025 self.node_id,
2026 place_fn,
2027 )
2028 }
2029
2030 fn min_intrinsic_width(&self, height: f32) -> f32 {
2031 let kind = IntrinsicKind::MinWidth(height);
2032 self.cache.activate(self.cache_epoch);
2033 if !self.force_remeasure.get() {
2034 if let Some(value) = self.cache.get_intrinsic(&kind) {
2035 return value;
2036 }
2037 }
2038 let constraints = Constraints {
2039 min_width: 0.0,
2040 max_width: f32::INFINITY,
2041 min_height: height,
2042 max_height: height,
2043 };
2044 if let Some(node) = self.intrinsic_measure(constraints) {
2045 let value = node.size.width;
2046 self.cache.store_intrinsic(kind, value);
2047 value
2048 } else {
2049 0.0
2050 }
2051 }
2052
2053 fn max_intrinsic_width(&self, height: f32) -> f32 {
2054 let kind = IntrinsicKind::MaxWidth(height);
2055 self.cache.activate(self.cache_epoch);
2056 if !self.force_remeasure.get() {
2057 if let Some(value) = self.cache.get_intrinsic(&kind) {
2058 return value;
2059 }
2060 }
2061 let constraints = Constraints {
2062 min_width: 0.0,
2063 max_width: f32::INFINITY,
2064 min_height: 0.0,
2065 max_height: height,
2066 };
2067 if let Some(node) = self.intrinsic_measure(constraints) {
2068 let value = node.size.width;
2069 self.cache.store_intrinsic(kind, value);
2070 value
2071 } else {
2072 0.0
2073 }
2074 }
2075
2076 fn min_intrinsic_height(&self, width: f32) -> f32 {
2077 let kind = IntrinsicKind::MinHeight(width);
2078 self.cache.activate(self.cache_epoch);
2079 if !self.force_remeasure.get() {
2080 if let Some(value) = self.cache.get_intrinsic(&kind) {
2081 return value;
2082 }
2083 }
2084 let constraints = Constraints {
2085 min_width: width,
2086 max_width: width,
2087 min_height: 0.0,
2088 max_height: f32::INFINITY,
2089 };
2090 if let Some(node) = self.intrinsic_measure(constraints) {
2091 let value = node.size.height;
2092 self.cache.store_intrinsic(kind, value);
2093 value
2094 } else {
2095 0.0
2096 }
2097 }
2098
2099 fn max_intrinsic_height(&self, width: f32) -> f32 {
2100 let kind = IntrinsicKind::MaxHeight(width);
2101 self.cache.activate(self.cache_epoch);
2102 if !self.force_remeasure.get() {
2103 if let Some(value) = self.cache.get_intrinsic(&kind) {
2104 return value;
2105 }
2106 }
2107 let constraints = Constraints {
2108 min_width: 0.0,
2109 max_width: width,
2110 min_height: 0.0,
2111 max_height: f32::INFINITY,
2112 };
2113 if let Some(node) = self.intrinsic_measure(constraints) {
2114 let value = node.size.height;
2115 self.cache.store_intrinsic(kind, value);
2116 value
2117 } else {
2118 0.0
2119 }
2120 }
2121
2122 fn flex_parent_data(&self) -> Option<cranpose_ui_layout::FlexParentData> {
2123 let Ok(mut applier) = self.applier.try_borrow_typed() else {
2126 return None;
2127 };
2128
2129 applier
2130 .with_node::<LayoutNode, _>(self.node_id, |layout_node| {
2131 let props = layout_node.resolved_modifiers().layout_properties();
2132 props.weight().map(|weight_data| {
2133 cranpose_ui_layout::FlexParentData::new(weight_data.weight, weight_data.fill)
2134 })
2135 })
2136 .ok()
2137 .flatten()
2138 }
2139}
2140
2141fn measure_node_with_host(
2142 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
2143 runtime_handle: Option<RuntimeHandle>,
2144 node_id: NodeId,
2145 constraints: Constraints,
2146 epoch: u64,
2147) -> Result<Rc<MeasuredNode>, NodeError> {
2148 let runtime_handle = match runtime_handle {
2149 Some(handle) => Some(handle),
2150 None => applier.borrow_typed().runtime_handle(),
2151 };
2152 let mut builder =
2153 LayoutBuilder::new_with_epoch(applier, epoch, Rc::new(RefCell::new(SlotTable::default())));
2154 builder.set_runtime_handle(runtime_handle);
2155 builder.measure_node(node_id, constraints)
2156}
2157
2158#[derive(Clone)]
2159struct RuntimeNodeMetadata {
2160 modifier: Modifier,
2161 resolved_modifiers: ResolvedModifiers,
2162 modifier_slices: Rc<ModifierNodeSlices>,
2163 role: SemanticsRole,
2164 button_handler: Option<Rc<RefCell<dyn FnMut()>>>,
2165}
2166
2167impl Default for RuntimeNodeMetadata {
2168 fn default() -> Self {
2169 Self {
2170 modifier: Modifier::empty(),
2171 resolved_modifiers: ResolvedModifiers::default(),
2172 modifier_slices: Rc::default(),
2173 role: SemanticsRole::Unknown,
2174 button_handler: None,
2175 }
2176 }
2177}
2178
2179fn role_from_modifier_slices(modifier_slices: &ModifierNodeSlices) -> SemanticsRole {
2180 modifier_slices
2181 .text_content()
2182 .map(|text| SemanticsRole::Text {
2183 value: text.to_string(),
2184 })
2185 .unwrap_or(SemanticsRole::Layout)
2186}
2187
2188fn runtime_metadata_for(
2189 applier: &mut MemoryApplier,
2190 node_id: NodeId,
2191) -> Result<RuntimeNodeMetadata, NodeError> {
2192 if let Ok(meta) = applier.with_node::<LayoutNode, _>(node_id, |layout| {
2197 let modifier = layout.modifier.clone();
2198 let resolved_modifiers = layout.resolved_modifiers();
2199 let modifier_slices = layout.modifier_slices_snapshot();
2200 let role = role_from_modifier_slices(&modifier_slices);
2201
2202 RuntimeNodeMetadata {
2203 modifier,
2204 resolved_modifiers,
2205 modifier_slices,
2206 role,
2207 button_handler: None,
2208 }
2209 }) {
2210 return Ok(meta);
2211 }
2212
2213 if let Ok((modifier, resolved_modifiers, modifier_slices)) = applier
2215 .with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
2216 (
2217 node.modifier(),
2218 node.resolved_modifiers(),
2219 node.modifier_slices_snapshot(),
2220 )
2221 })
2222 {
2223 return Ok(RuntimeNodeMetadata {
2224 modifier,
2225 resolved_modifiers,
2226 modifier_slices,
2227 role: SemanticsRole::Subcompose,
2228 button_handler: None,
2229 });
2230 }
2231 Ok(RuntimeNodeMetadata::default())
2232}
2233
2234fn clear_semantics_dirty_flags(
2235 applier: &mut MemoryApplier,
2236 node: &MeasuredNode,
2237) -> Result<(), NodeError> {
2238 match applier.with_node::<LayoutNode, _>(node.node_id, |layout| {
2239 layout.clear_needs_semantics();
2240 }) {
2241 Ok(()) => {}
2242 Err(NodeError::Missing { .. }) => {}
2243 Err(NodeError::TypeMismatch { .. }) => {
2244 match applier.with_node::<SubcomposeLayoutNode, _>(node.node_id, |subcompose| {
2245 subcompose.clear_needs_semantics();
2246 }) {
2247 Ok(()) | Err(NodeError::Missing { .. }) | Err(NodeError::TypeMismatch { .. }) => {}
2248 Err(err) => return Err(err),
2249 }
2250 }
2251 Err(err) => return Err(err),
2252 }
2253
2254 for child in &node.children {
2255 clear_semantics_dirty_flags(applier, &child.node)?;
2256 }
2257
2258 Ok(())
2259}
2260
2261fn build_semantics_tree_from_live_nodes(
2262 applier: &mut MemoryApplier,
2263 node: &MeasuredNode,
2264) -> Result<SemanticsTree, NodeError> {
2265 Ok(SemanticsTree::new(build_semantics_node_from_live_nodes(
2266 applier, node,
2267 )?))
2268}
2269
2270fn semantics_node_from_parts(
2271 node_id: NodeId,
2272 mut role: SemanticsRole,
2273 config: Option<SemanticsConfiguration>,
2274 children: Vec<SemanticsNode>,
2275) -> SemanticsNode {
2276 let mut actions = Vec::new();
2277 let mut description = None;
2278
2279 if let Some(config) = config {
2280 if config.is_button {
2281 role = SemanticsRole::Button;
2282 }
2283 if config.is_clickable {
2284 actions.push(SemanticsAction::Click {
2285 handler: SemanticsCallback::new(node_id),
2286 });
2287 }
2288 description = config.content_description;
2289 }
2290
2291 SemanticsNode::new(node_id, role, actions, children, description)
2292}
2293
2294fn build_semantics_node_from_live_nodes(
2295 applier: &mut MemoryApplier,
2296 node: &MeasuredNode,
2297) -> Result<SemanticsNode, NodeError> {
2298 let (role, config) = match applier.with_node::<LayoutNode, _>(node.node_id, |layout| {
2299 let role = role_from_modifier_slices(&layout.modifier_slices_snapshot());
2300 let config = layout.semantics_configuration();
2301 layout.clear_needs_semantics();
2302 (role, config)
2303 }) {
2304 Ok(data) => data,
2305 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {
2306 match applier.with_node::<SubcomposeLayoutNode, _>(node.node_id, |subcompose| {
2307 subcompose.clear_needs_semantics();
2308 (
2309 SemanticsRole::Subcompose,
2310 collect_semantics_from_modifier(&subcompose.modifier()),
2311 )
2312 }) {
2313 Ok(data) => data,
2314 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {
2315 (SemanticsRole::Unknown, None)
2316 }
2317 Err(err) => return Err(err),
2318 }
2319 }
2320 Err(err) => return Err(err),
2321 };
2322
2323 let mut children = Vec::with_capacity(node.children.len());
2324 for child in &node.children {
2325 children.push(build_semantics_node_from_live_nodes(applier, &child.node)?);
2326 }
2327
2328 Ok(semantics_node_from_parts(
2329 node.node_id,
2330 role,
2331 config,
2332 children,
2333 ))
2334}
2335
2336fn record_semantics_allocation_stats(node: &SemanticsNode, stats: &mut LayoutAllocationDebugStats) {
2337 stats.semantics_node_count += 1;
2338 stats.semantics_action_count += node.actions.len();
2339 stats.semantics_action_capacity += node.actions.capacity();
2340 stats.semantics_child_count += node.children.len();
2341 stats.semantics_child_capacity += node.children.capacity();
2342 stats.semantics_heap_bytes += node.actions.capacity() * size_of::<SemanticsAction>();
2343 stats.semantics_heap_bytes += node.children.capacity() * size_of::<SemanticsNode>();
2344
2345 if let Some(description) = &node.description {
2346 stats.semantics_description_count += 1;
2347 stats.semantics_description_bytes += description.capacity();
2348 stats.semantics_heap_bytes += description.capacity();
2349 }
2350 if let SemanticsRole::Text { value } = &node.role {
2351 stats.semantics_text_role_bytes += value.capacity();
2352 stats.semantics_heap_bytes += value.capacity();
2353 }
2354
2355 for child in &node.children {
2356 record_semantics_allocation_stats(child, stats);
2357 }
2358}
2359
2360fn record_layout_box_allocation_stats(
2361 layout_box: &LayoutBox,
2362 stats: &mut LayoutAllocationDebugStats,
2363) {
2364 stats.layout_box_count += 1;
2365 stats.layout_box_child_count += layout_box.children.len();
2366 stats.layout_box_child_capacity += layout_box.children.capacity();
2367 stats.layout_box_heap_bytes += layout_box.children.capacity() * size_of::<LayoutBox>();
2368 stats.add_modifier_slice(layout_box.node_data.modifier_slices().debug_stats());
2369
2370 for child in &layout_box.children {
2371 record_layout_box_allocation_stats(child, stats);
2372 }
2373}
2374
2375fn build_layout_tree(
2376 applier: &mut MemoryApplier,
2377 node: &MeasuredNode,
2378) -> Result<LayoutTree, NodeError> {
2379 fn place(
2380 applier: &mut MemoryApplier,
2381 node: &MeasuredNode,
2382 origin: Point,
2383 ) -> Result<LayoutBox, NodeError> {
2384 let top_left = Point {
2386 x: origin.x + node.offset.x,
2387 y: origin.y + node.offset.y,
2388 };
2389 let rect = GeometryRect {
2390 x: top_left.x,
2391 y: top_left.y,
2392 width: node.size.width,
2393 height: node.size.height,
2394 };
2395 let info = runtime_metadata_for(applier, node.node_id)?;
2396 let kind = layout_kind_from_metadata(node.node_id, &info);
2397 let RuntimeNodeMetadata {
2398 modifier,
2399 resolved_modifiers,
2400 modifier_slices,
2401 ..
2402 } = info;
2403 let data = LayoutNodeData::new(modifier, resolved_modifiers, modifier_slices, kind);
2404 let mut children = Vec::with_capacity(node.children.len());
2405 for child in &node.children {
2406 let child_origin = Point {
2407 x: top_left.x + child.offset.x,
2408 y: top_left.y + child.offset.y,
2409 };
2410 children.push(place(applier, &child.node, child_origin)?);
2411 }
2412 Ok(LayoutBox::new(
2413 node.node_id,
2414 rect,
2415 node.content_offset,
2416 data,
2417 children,
2418 ))
2419 }
2420
2421 Ok(LayoutTree::new(place(
2422 applier,
2423 node,
2424 Point { x: 0.0, y: 0.0 },
2425 )?))
2426}
2427
2428fn semantics_role_from_layout_box(layout_box: &LayoutBox) -> SemanticsRole {
2429 match &layout_box.node_data.kind {
2430 LayoutNodeKind::Subcompose => SemanticsRole::Subcompose,
2431 LayoutNodeKind::Spacer => SemanticsRole::Spacer,
2432 LayoutNodeKind::Unknown => SemanticsRole::Unknown,
2433 LayoutNodeKind::Button { .. } => SemanticsRole::Button,
2434 LayoutNodeKind::Layout => layout_box
2435 .node_data
2436 .modifier_slices()
2437 .text_content()
2438 .map(|text| SemanticsRole::Text {
2439 value: text.to_string(),
2440 })
2441 .unwrap_or(SemanticsRole::Layout),
2442 }
2443}
2444
2445fn build_semantics_node_from_layout_box(layout_box: &LayoutBox) -> SemanticsNode {
2446 let children = layout_box
2447 .children
2448 .iter()
2449 .map(build_semantics_node_from_layout_box)
2450 .collect();
2451
2452 semantics_node_from_parts(
2453 layout_box.node_id,
2454 semantics_role_from_layout_box(layout_box),
2455 collect_semantics_from_modifier(&layout_box.node_data.modifier),
2456 children,
2457 )
2458}
2459
2460fn layout_kind_from_metadata(_node_id: NodeId, info: &RuntimeNodeMetadata) -> LayoutNodeKind {
2461 match &info.role {
2462 SemanticsRole::Layout => LayoutNodeKind::Layout,
2463 SemanticsRole::Subcompose => LayoutNodeKind::Subcompose,
2464 SemanticsRole::Text { .. } => {
2465 LayoutNodeKind::Layout
2469 }
2470 SemanticsRole::Spacer => LayoutNodeKind::Spacer,
2471 SemanticsRole::Button => {
2472 let handler = info
2473 .button_handler
2474 .as_ref()
2475 .cloned()
2476 .unwrap_or_else(|| Rc::new(RefCell::new(|| {})));
2477 LayoutNodeKind::Button { on_click: handler }
2478 }
2479 SemanticsRole::Unknown => LayoutNodeKind::Unknown,
2480 }
2481}
2482
2483fn subtract_padding(constraints: Constraints, padding: EdgeInsets) -> Constraints {
2484 let horizontal = padding.horizontal_sum();
2485 let vertical = padding.vertical_sum();
2486 let min_width = (constraints.min_width - horizontal).max(0.0);
2487 let mut max_width = constraints.max_width;
2488 if max_width.is_finite() {
2489 max_width = (max_width - horizontal).max(0.0);
2490 }
2491 let min_height = (constraints.min_height - vertical).max(0.0);
2492 let mut max_height = constraints.max_height;
2493 if max_height.is_finite() {
2494 max_height = (max_height - vertical).max(0.0);
2495 }
2496 normalize_constraints(Constraints {
2497 min_width,
2498 max_width,
2499 min_height,
2500 max_height,
2501 })
2502}
2503
2504#[cfg(test)]
2505pub(crate) fn align_horizontal(alignment: HorizontalAlignment, available: f32, child: f32) -> f32 {
2506 match alignment {
2507 HorizontalAlignment::Start => 0.0,
2508 HorizontalAlignment::CenterHorizontally => ((available - child) / 2.0).max(0.0),
2509 HorizontalAlignment::End => (available - child).max(0.0),
2510 }
2511}
2512
2513#[cfg(test)]
2514pub(crate) fn align_vertical(alignment: VerticalAlignment, available: f32, child: f32) -> f32 {
2515 match alignment {
2516 VerticalAlignment::Top => 0.0,
2517 VerticalAlignment::CenterVertically => ((available - child) / 2.0).max(0.0),
2518 VerticalAlignment::Bottom => (available - child).max(0.0),
2519 }
2520}
2521
2522fn resolve_dimension(
2523 base: f32,
2524 explicit: DimensionConstraint,
2525 min_override: Option<f32>,
2526 max_override: Option<f32>,
2527 min_limit: f32,
2528 max_limit: f32,
2529) -> f32 {
2530 let mut min_bound = min_limit;
2531 if let Some(min_value) = min_override {
2532 min_bound = min_bound.max(min_value);
2533 }
2534
2535 let mut max_bound = if max_limit.is_finite() {
2536 max_limit
2537 } else {
2538 max_override.unwrap_or(max_limit)
2539 };
2540 if let Some(max_value) = max_override {
2541 if max_bound.is_finite() {
2542 max_bound = max_bound.min(max_value);
2543 } else {
2544 max_bound = max_value;
2545 }
2546 }
2547 if max_bound < min_bound {
2548 max_bound = min_bound;
2549 }
2550
2551 let mut size = match explicit {
2552 DimensionConstraint::Points(points) => points,
2553 DimensionConstraint::Fraction(fraction) => {
2554 if max_limit.is_finite() {
2555 max_limit * fraction.clamp(0.0, 1.0)
2556 } else {
2557 base
2558 }
2559 }
2560 DimensionConstraint::Unspecified => base,
2561 DimensionConstraint::Intrinsic(_) => base,
2564 };
2565
2566 size = clamp_dimension(size, min_bound, max_bound);
2567 size = clamp_dimension(size, min_limit, max_limit);
2568 size.max(0.0)
2569}
2570
2571fn clamp_dimension(value: f32, min: f32, max: f32) -> f32 {
2572 let mut result = value.max(min);
2573 if max.is_finite() {
2574 result = result.min(max);
2575 }
2576 result
2577}
2578
2579fn normalize_constraints(mut constraints: Constraints) -> Constraints {
2580 if constraints.max_width < constraints.min_width {
2581 constraints.max_width = constraints.min_width;
2582 }
2583 if constraints.max_height < constraints.min_height {
2584 constraints.max_height = constraints.min_height;
2585 }
2586 constraints
2587}
2588
2589#[cfg(test)]
2590#[path = "tests/layout_tests.rs"]
2591mod tests;