1pub mod core;
2pub mod policies;
3
4use std::{
5 cell::{Cell, RefCell},
6 fmt,
7 mem::size_of,
8 rc::Rc,
9};
10
11use cranpose_core::{
12 Applier, ApplierHost, Composer, ConcreteApplierHost, MemoryApplier, Node, NodeError, NodeId,
13 Phase, RuntimeHandle, SlotTable, SlotsHost, SnapshotStateObserver,
14};
15
16use self::core::Measurable;
17use self::core::Placeable;
18#[cfg(test)]
19use self::core::{HorizontalAlignment, VerticalAlignment};
20use crate::modifier::{
21 collect_semantics_from_modifier, DimensionConstraint, EdgeInsets, Modifier, ModifierNodeSlices,
22 ModifierNodeSlicesDebugStats, Point, Rect as GeometryRect, ResolvedModifiers, Size,
23};
24
25use crate::subcompose_layout::SubcomposeLayoutNode;
26use crate::widgets::nodes::{IntrinsicKind, LayoutNode, LayoutNodeCacheHandles, LayoutState};
27use cranpose_foundation::{
28 text::TextRange, InvalidationKind, ModifierNodeContext, NodeCapabilities,
29 SemanticsConfiguration,
30};
31use cranpose_ui_layout::{Constraints, MeasurePolicy, Placement};
32
33#[derive(Default)]
38pub(crate) struct LayoutNodeContext {
39 invalidations: Vec<InvalidationKind>,
40 update_requested: bool,
41 active_capabilities: Vec<NodeCapabilities>,
42}
43
44impl LayoutNodeContext {
45 pub(crate) fn new() -> Self {
46 Self::default()
47 }
48
49 pub(crate) fn take_invalidations(&mut self) -> Vec<InvalidationKind> {
50 std::mem::take(&mut self.invalidations)
51 }
52}
53
54impl ModifierNodeContext for LayoutNodeContext {
55 fn invalidate(&mut self, kind: InvalidationKind) {
56 if !self.invalidations.contains(&kind) {
57 self.invalidations.push(kind);
58 }
59 }
60
61 fn request_update(&mut self) {
62 self.update_requested = true;
63 }
64
65 fn push_active_capabilities(&mut self, capabilities: NodeCapabilities) {
66 self.active_capabilities.push(capabilities);
67 }
68
69 fn pop_active_capabilities(&mut self) {
70 self.active_capabilities.pop();
71 }
72}
73
74#[doc(hidden)]
97pub fn invalidate_all_layout_caches() {
98 crate::render_state::invalidate_layout_cache_epoch();
99}
100
101struct ApplierSlotGuard<'a> {
112 target: &'a mut MemoryApplier,
114 host: Rc<ConcreteApplierHost<MemoryApplier>>,
116 slots: Rc<RefCell<SlotTable>>,
119}
120
121impl<'a> ApplierSlotGuard<'a> {
122 fn new(target: &'a mut MemoryApplier) -> Self {
126 let original_applier = std::mem::replace(target, MemoryApplier::new());
128 let host = Rc::new(ConcreteApplierHost::new(original_applier));
129
130 let slots = {
132 let mut applier_ref = host.borrow_typed();
133 std::mem::take(applier_ref.slots())
134 };
135 let slots = Rc::new(RefCell::new(slots));
136
137 Self {
138 target,
139 host,
140 slots,
141 }
142 }
143
144 fn host(&self) -> Rc<ConcreteApplierHost<MemoryApplier>> {
146 Rc::clone(&self.host)
147 }
148
149 fn slots_handle(&self) -> Rc<RefCell<SlotTable>> {
152 Rc::clone(&self.slots)
153 }
154}
155
156impl Drop for ApplierSlotGuard<'_> {
157 fn drop(&mut self) {
158 {
162 let mut applier_ref = self.host.borrow_typed();
163 *applier_ref.slots() = std::mem::take(&mut *self.slots.borrow_mut());
164 }
165
166 {
168 let mut applier_ref = self.host.borrow_typed();
169 let original_applier = std::mem::take(&mut *applier_ref);
170 let _ = std::mem::replace(self.target, original_applier);
171 }
172 }
174}
175
176struct ModifierChainMeasurement {
178 size: Size,
179 content_offset: Point,
181 offset: Point,
183}
184
185type LayoutModifierNodeData = (
186 usize,
187 Rc<RefCell<Box<dyn cranpose_foundation::ModifierNode>>>,
188);
189
190struct ScratchVecPool<T> {
191 available: Vec<Vec<T>>,
192}
193
194impl<T> ScratchVecPool<T> {
195 fn acquire(&mut self) -> Vec<T> {
196 self.available.pop().unwrap_or_default()
197 }
198
199 fn release(&mut self, mut values: Vec<T>) {
200 values.clear();
201 self.available.push(values);
202 }
203
204 #[cfg(test)]
205 fn available_count(&self) -> usize {
206 self.available.len()
207 }
208}
209
210impl<T> Default for ScratchVecPool<T> {
211 fn default() -> Self {
212 Self {
213 available: Vec::new(),
214 }
215 }
216}
217
218#[derive(Default)]
219pub(crate) struct FrameLayoutArena {
220 tmp_records: ScratchVecPool<(NodeId, ChildRecord)>,
221 tmp_child_ids: ScratchVecPool<NodeId>,
222 tmp_layout_node_data: ScratchVecPool<LayoutModifierNodeData>,
223 tmp_placements: ScratchVecPool<Placement>,
224}
225
226#[cfg(test)]
227impl FrameLayoutArena {
228 pub(crate) fn available_placement_scratch_count(&self) -> usize {
229 self.tmp_placements.available_count()
230 }
231
232 pub(crate) fn seed_placement_scratch_for_test(&mut self) {
233 self.tmp_placements.release(Vec::with_capacity(1));
234 }
235}
236
237#[derive(Clone, Debug, PartialEq, Eq)]
239pub struct SemanticsCallback {
240 node_id: NodeId,
241}
242
243impl SemanticsCallback {
244 pub fn new(node_id: NodeId) -> Self {
245 Self { node_id }
246 }
247
248 pub fn node_id(&self) -> NodeId {
249 self.node_id
250 }
251}
252
253#[derive(Clone, Debug, PartialEq, Eq)]
255pub enum SemanticsAction {
256 Click { handler: SemanticsCallback },
257}
258
259#[derive(Clone, Debug, PartialEq, Eq)]
262pub enum SemanticsRole {
263 Layout,
265 Subcompose,
267 Text { value: String },
269 Spacer,
271 Button,
273 Unknown,
275}
276
277#[derive(Clone, Debug, PartialEq, Eq)]
279pub struct SemanticsNode {
280 pub node_id: NodeId,
281 pub role: SemanticsRole,
282 pub actions: Vec<SemanticsAction>,
283 pub children: Vec<SemanticsNode>,
284 pub description: Option<String>,
285 pub editable_text: bool,
286 pub text_selection: Option<TextRange>,
287}
288
289impl SemanticsNode {
290 fn new(
291 node_id: NodeId,
292 role: SemanticsRole,
293 actions: Vec<SemanticsAction>,
294 children: Vec<SemanticsNode>,
295 description: Option<String>,
296 editable_text: bool,
297 text_selection: Option<TextRange>,
298 ) -> Self {
299 Self {
300 node_id,
301 role,
302 actions,
303 children,
304 description,
305 editable_text,
306 text_selection,
307 }
308 }
309}
310
311#[derive(Clone, Debug, PartialEq, Eq)]
313pub struct SemanticsTree {
314 root: SemanticsNode,
315}
316
317impl SemanticsTree {
318 fn new(root: SemanticsNode) -> Self {
319 Self { root }
320 }
321
322 pub fn root(&self) -> &SemanticsNode {
323 &self.root
324 }
325}
326
327#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
328pub struct LayoutAllocationDebugStats {
329 pub layout_box_count: usize,
330 pub layout_box_child_count: usize,
331 pub layout_box_child_capacity: usize,
332 pub layout_box_heap_bytes: usize,
333 pub modifier_slice_count: usize,
334 pub modifier_slice_heap_bytes: usize,
335 pub modifier_draw_command_count: usize,
336 pub modifier_draw_command_capacity: usize,
337 pub modifier_pointer_input_count: usize,
338 pub modifier_pointer_input_capacity: usize,
339 pub modifier_click_handler_count: usize,
340 pub modifier_click_handler_capacity: usize,
341 pub modifier_text_content_count: usize,
342 pub modifier_text_style_count: usize,
343 pub modifier_text_layout_options_count: usize,
344 pub modifier_prepared_text_layout_count: usize,
345 pub modifier_graphics_layer_count: usize,
346 pub modifier_graphics_layer_resolver_count: usize,
347 pub semantics_node_count: usize,
348 pub semantics_action_count: usize,
349 pub semantics_action_capacity: usize,
350 pub semantics_child_count: usize,
351 pub semantics_child_capacity: usize,
352 pub semantics_description_count: usize,
353 pub semantics_description_bytes: usize,
354 pub semantics_text_role_bytes: usize,
355 pub semantics_heap_bytes: usize,
356}
357
358impl LayoutAllocationDebugStats {
359 fn add_modifier_slice(&mut self, stats: ModifierNodeSlicesDebugStats) {
360 self.modifier_slice_count += 1;
361 self.modifier_slice_heap_bytes += stats.heap_bytes;
362 self.modifier_draw_command_count += stats.draw_command_count;
363 self.modifier_draw_command_capacity += stats.draw_command_capacity;
364 self.modifier_pointer_input_count += stats.pointer_input_count;
365 self.modifier_pointer_input_capacity += stats.pointer_input_capacity;
366 self.modifier_click_handler_count += stats.click_handler_count;
367 self.modifier_click_handler_capacity += stats.click_handler_capacity;
368 self.modifier_text_content_count += usize::from(stats.has_text_content);
369 self.modifier_text_style_count += usize::from(stats.has_text_style);
370 self.modifier_text_layout_options_count += usize::from(stats.has_text_layout_options);
371 self.modifier_prepared_text_layout_count += usize::from(stats.has_prepared_text_layout);
372 self.modifier_graphics_layer_count += usize::from(stats.has_graphics_layer);
373 self.modifier_graphics_layer_resolver_count +=
374 usize::from(stats.has_graphics_layer_resolver);
375 }
376}
377
378#[derive(Debug, Clone)]
380pub struct LayoutTree {
381 root: LayoutBox,
382}
383
384impl LayoutTree {
385 pub fn new(root: LayoutBox) -> Self {
386 Self { root }
387 }
388
389 pub fn root(&self) -> &LayoutBox {
390 &self.root
391 }
392
393 pub fn root_mut(&mut self) -> &mut LayoutBox {
394 &mut self.root
395 }
396
397 pub fn into_root(self) -> LayoutBox {
398 self.root
399 }
400
401 pub fn debug_allocation_stats(&self) -> LayoutAllocationDebugStats {
402 let mut stats = LayoutAllocationDebugStats::default();
403 record_layout_box_allocation_stats(&self.root, &mut stats);
404 stats
405 }
406}
407
408#[derive(Debug, Clone)]
410pub struct LayoutBox {
411 pub node_id: NodeId,
412 pub rect: GeometryRect,
413 pub content_offset: Point,
415 pub node_data: LayoutNodeData,
416 pub children: Vec<LayoutBox>,
417}
418
419impl LayoutBox {
420 pub fn new(
421 node_id: NodeId,
422 rect: GeometryRect,
423 content_offset: Point,
424 node_data: LayoutNodeData,
425 children: Vec<LayoutBox>,
426 ) -> Self {
427 Self {
428 node_id,
429 rect,
430 content_offset,
431 node_data,
432 children,
433 }
434 }
435}
436
437#[derive(Debug, Clone)]
439pub struct LayoutNodeData {
440 pub modifier: Modifier,
441 pub resolved_modifiers: ResolvedModifiers,
442 pub modifier_slices: Rc<ModifierNodeSlices>,
443 pub kind: LayoutNodeKind,
444}
445
446impl LayoutNodeData {
447 pub fn new(
448 modifier: Modifier,
449 resolved_modifiers: ResolvedModifiers,
450 modifier_slices: Rc<ModifierNodeSlices>,
451 kind: LayoutNodeKind,
452 ) -> Self {
453 Self {
454 modifier,
455 resolved_modifiers,
456 modifier_slices,
457 kind,
458 }
459 }
460
461 pub fn resolved_modifiers(&self) -> ResolvedModifiers {
462 self.resolved_modifiers
463 }
464
465 pub fn modifier_slices(&self) -> &ModifierNodeSlices {
466 &self.modifier_slices
467 }
468}
469
470#[derive(Clone)]
477pub enum LayoutNodeKind {
478 Layout,
479 Subcompose,
480 Spacer,
481 Button { on_click: Rc<RefCell<dyn FnMut()>> },
482 Unknown,
483}
484
485impl fmt::Debug for LayoutNodeKind {
486 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
487 match self {
488 LayoutNodeKind::Layout => f.write_str("Layout"),
489 LayoutNodeKind::Subcompose => f.write_str("Subcompose"),
490 LayoutNodeKind::Spacer => f.write_str("Spacer"),
491 LayoutNodeKind::Button { .. } => f.write_str("Button"),
492 LayoutNodeKind::Unknown => f.write_str("Unknown"),
493 }
494 }
495}
496
497pub trait LayoutEngine {
499 fn compute_layout(&mut self, root: NodeId, max_size: Size) -> Result<LayoutTree, NodeError>;
500}
501
502impl LayoutEngine for MemoryApplier {
503 fn compute_layout(&mut self, root: NodeId, max_size: Size) -> Result<LayoutTree, NodeError> {
504 let measurements = measure_layout(self, root, max_size)?;
505 measurements
506 .into_layout_tree()
507 .ok_or(NodeError::MissingContext {
508 id: root,
509 reason: "layout tree was not requested",
510 })
511 }
512}
513
514#[derive(Debug, Clone)]
516pub struct LayoutMeasurements {
517 root: Rc<MeasuredNode>,
518 semantics: Option<SemanticsTree>,
519 layout_tree: Option<LayoutTree>,
520}
521
522impl LayoutMeasurements {
523 fn new(
524 root: Rc<MeasuredNode>,
525 semantics: Option<SemanticsTree>,
526 layout_tree: Option<LayoutTree>,
527 ) -> Self {
528 Self {
529 root,
530 semantics,
531 layout_tree,
532 }
533 }
534
535 pub fn root_size(&self) -> Size {
537 self.root.size
538 }
539
540 pub fn semantics_tree(&self) -> Option<&SemanticsTree> {
541 self.semantics.as_ref()
542 }
543
544 pub fn debug_allocation_stats(&self) -> LayoutAllocationDebugStats {
545 let mut stats = self
546 .layout_tree
547 .as_ref()
548 .map(LayoutTree::debug_allocation_stats)
549 .unwrap_or_default();
550 if let Some(semantics) = &self.semantics {
551 record_semantics_allocation_stats(semantics.root(), &mut stats);
552 }
553 stats
554 }
555
556 pub fn into_layout_tree(self) -> Option<LayoutTree> {
558 self.layout_tree
559 }
560
561 pub fn layout_tree(&self) -> Option<LayoutTree> {
563 self.layout_tree.clone()
564 }
565}
566
567pub fn build_semantics_tree_from_layout_tree(layout_tree: &LayoutTree) -> SemanticsTree {
572 SemanticsTree::new(build_semantics_node_from_layout_box(layout_tree.root()))
573}
574
575pub fn build_layout_tree_from_applier(
581 applier: &mut MemoryApplier,
582 root: NodeId,
583) -> Result<Option<LayoutTree>, NodeError> {
584 fn snapshot(
585 applier: &mut MemoryApplier,
586 node_id: NodeId,
587 ) -> Result<Option<(crate::widgets::nodes::layout_node::LayoutState, Vec<NodeId>)>, NodeError>
588 {
589 match applier.with_node::<LayoutNode, _>(node_id, |node| {
590 (node.layout_state(), node.children.clone())
591 }) {
592 Ok(snapshot) => return Ok(Some(snapshot)),
593 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {}
594 Err(err) => return Err(err),
595 }
596
597 match applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
598 (node.layout_state(), node.active_children())
599 }) {
600 Ok(snapshot) => Ok(Some(snapshot)),
601 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => Ok(None),
602 Err(err) => Err(err),
603 }
604 }
605
606 fn place(
607 applier: &mut MemoryApplier,
608 node_id: NodeId,
609 parent_content_origin: Point,
610 ) -> Result<Option<LayoutBox>, NodeError> {
611 let Some((state, child_ids)) = snapshot(applier, node_id)? else {
612 return Ok(None);
613 };
614 if !state.is_placed {
615 return Ok(None);
616 }
617
618 let top_left = Point {
619 x: parent_content_origin.x + state.position.x,
620 y: parent_content_origin.y + state.position.y,
621 };
622 let rect = GeometryRect {
623 x: top_left.x,
624 y: top_left.y,
625 width: state.size.width,
626 height: state.size.height,
627 };
628 let info = runtime_metadata_for(applier, node_id)?;
629 let kind = layout_kind_from_metadata(node_id, &info);
630 let RuntimeNodeMetadata {
631 modifier,
632 resolved_modifiers,
633 modifier_slices,
634 ..
635 } = info;
636 let data = LayoutNodeData::new(modifier, resolved_modifiers, modifier_slices, kind);
637 let child_origin = Point {
638 x: top_left.x + state.content_offset.x,
639 y: top_left.y + state.content_offset.y,
640 };
641 let mut children = Vec::with_capacity(child_ids.len());
642 for child_id in child_ids {
643 if let Some(child) = place(applier, child_id, child_origin)? {
644 children.push(child);
645 }
646 }
647
648 Ok(Some(LayoutBox::new(
649 node_id,
650 rect,
651 state.content_offset,
652 data,
653 children,
654 )))
655 }
656
657 place(applier, root, Point::default()).map(|root| root.map(LayoutTree::new))
658}
659
660pub fn build_semantics_tree_from_applier(
666 applier: &mut MemoryApplier,
667 root: NodeId,
668) -> Result<Option<SemanticsTree>, NodeError> {
669 fn node(
670 applier: &mut MemoryApplier,
671 node_id: NodeId,
672 ) -> Result<Option<SemanticsNode>, NodeError> {
673 match applier.with_node::<LayoutNode, _>(node_id, |layout| {
674 let state = layout.layout_state();
675 if !state.is_placed {
676 return None;
677 }
678 let role = role_from_modifier_slices(&layout.modifier_slices_snapshot());
679 let config = layout.semantics_configuration();
680 let children = layout.children.clone();
681 layout.clear_needs_semantics();
682 Some((role, config, children))
683 }) {
684 Ok(Some((role, config, child_ids))) => {
685 let mut children = Vec::with_capacity(child_ids.len());
686 for child_id in child_ids {
687 if let Some(child) = node(applier, child_id)? {
688 children.push(child);
689 }
690 }
691 return Ok(Some(semantics_node_from_parts(
692 node_id, role, config, children,
693 )));
694 }
695 Ok(None) => return Ok(None),
696 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {}
697 Err(err) => return Err(err),
698 }
699
700 match applier.with_node::<SubcomposeLayoutNode, _>(node_id, |subcompose| {
701 let state = subcompose.layout_state();
702 if !state.is_placed {
703 return None;
704 }
705 let config = collect_semantics_from_modifier(&subcompose.modifier());
706 let children = subcompose.active_children();
707 subcompose.clear_needs_semantics();
708 Some((config, children))
709 }) {
710 Ok(Some((config, child_ids))) => {
711 let mut children = Vec::with_capacity(child_ids.len());
712 for child_id in child_ids {
713 if let Some(child) = node(applier, child_id)? {
714 children.push(child);
715 }
716 }
717 Ok(Some(semantics_node_from_parts(
718 node_id,
719 SemanticsRole::Subcompose,
720 config,
721 children,
722 )))
723 }
724 Ok(None) | Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {
725 Ok(None)
726 }
727 Err(err) => Err(err),
728 }
729 }
730
731 node(applier, root).map(|root| root.map(SemanticsTree::new))
732}
733
734#[derive(Clone, Copy, Debug, PartialEq, Eq)]
735pub struct MeasureLayoutOptions {
736 pub collect_semantics: bool,
737 pub build_layout_tree: bool,
738}
739
740impl Default for MeasureLayoutOptions {
741 fn default() -> Self {
742 Self {
743 collect_semantics: true,
744 build_layout_tree: true,
745 }
746 }
747}
748
749pub fn tree_needs_layout(applier: &mut dyn Applier, root: NodeId) -> Result<bool, NodeError> {
757 Ok(applier.get_mut(root)?.needs_layout())
758}
759
760pub fn tree_needs_semantics(applier: &mut dyn Applier, root: NodeId) -> Result<bool, NodeError> {
766 Ok(applier.get_mut(root)?.needs_semantics())
767}
768
769#[cfg(test)]
771pub(crate) fn bubble_layout_dirty(applier: &mut MemoryApplier, node_id: NodeId) {
772 cranpose_core::bubble_layout_dirty(applier as &mut dyn Applier, node_id);
773}
774
775pub fn measure_layout(
777 applier: &mut MemoryApplier,
778 root: NodeId,
779 max_size: Size,
780) -> Result<LayoutMeasurements, NodeError> {
781 measure_layout_with_options(applier, root, max_size, MeasureLayoutOptions::default())
782}
783
784pub fn measure_layout_with_options(
785 applier: &mut MemoryApplier,
786 root: NodeId,
787 max_size: Size,
788 options: MeasureLayoutOptions,
789) -> Result<LayoutMeasurements, NodeError> {
790 process_pending_layout_repasses(applier, root)?;
791
792 let constraints = Constraints {
793 min_width: 0.0,
794 max_width: max_size.width,
795 min_height: 0.0,
796 max_height: max_size.height,
797 };
798
799 let (needs_remeasure, _needs_semantics, cached_epoch) = match applier
810 .with_node::<LayoutNode, _>(root, |node| {
811 (
812 node.needs_measure(), node.needs_semantics(),
814 node.cache_handles().epoch(),
815 )
816 }) {
817 Ok(tuple) => tuple,
818 Err(NodeError::TypeMismatch { .. }) => {
819 let node = applier.get_mut(root)?;
820 let measure_dirty = node.needs_measure();
824 let semantics_dirty = node.needs_semantics();
825 (measure_dirty, semantics_dirty, 0)
826 }
827 Err(err) => return Err(err),
828 };
829
830 let epoch = if needs_remeasure {
831 crate::render_state::next_layout_cache_epoch()
832 } else if cached_epoch != 0 {
833 cached_epoch
834 } else {
835 crate::render_state::current_layout_cache_epoch()
837 };
838
839 let guard = ApplierSlotGuard::new(applier);
847 let applier_host = guard.host();
848 let slots_handle = guard.slots_handle();
849
850 let frame_arena = crate::render_state::take_layout_frame_arena();
853 let mut builder = LayoutBuilder::new_with_epoch(
854 Rc::clone(&applier_host),
855 epoch,
856 Rc::clone(&slots_handle),
857 frame_arena,
858 );
859
860 let measured = builder.measure_node(root, normalize_constraints(constraints))?;
865
866 if let Ok(mut applier) = applier_host.try_borrow_typed() {
870 if applier
871 .with_node::<LayoutNode, _>(root, |node| {
872 node.set_position(Point::default());
873 })
874 .is_err()
875 {
876 let _ = applier.with_node::<SubcomposeLayoutNode, _>(root, |node| {
877 node.set_position(Point::default());
878 });
879 }
880 }
881
882 let (layout_tree, semantics) = {
883 let mut applier_ref = applier_host.borrow_typed();
884 let layout_tree = if options.build_layout_tree {
885 Some(build_layout_tree(&mut applier_ref, &measured)?)
886 } else {
887 None
888 };
889 let semantics = if options.collect_semantics {
890 let semantics_tree = if let Some(layout_tree) = layout_tree.as_ref() {
891 clear_semantics_dirty_flags(&mut applier_ref, &measured)?;
892 build_semantics_tree_from_layout_tree(layout_tree)
893 } else {
894 build_semantics_tree_from_live_nodes(&mut applier_ref, &measured)?
895 };
896 Some(semantics_tree)
897 } else {
898 None
899 };
900 (layout_tree, semantics)
901 };
902
903 drop(builder);
906
907 Ok(LayoutMeasurements::new(measured, semantics, layout_tree))
911}
912
913fn process_pending_layout_repasses(
914 applier: &mut MemoryApplier,
915 root: NodeId,
916) -> Result<(), NodeError> {
917 for node_id in crate::render_state::take_modifier_slice_repass_nodes() {
918 if let Ok(node) = applier.get_mut(node_id) {
919 let any = node.as_any_mut();
920 if let Some(layout) = any.downcast_mut::<crate::widgets::nodes::LayoutNode>() {
921 layout.mark_modifier_slices_dirty();
922 } else if let Some(subcompose) =
923 any.downcast_mut::<crate::subcompose_layout::SubcomposeLayoutNode>()
924 {
925 subcompose.mark_modifier_slices_dirty();
926 }
927 }
928 }
929 let repass_nodes = crate::take_layout_repass_nodes();
930 if repass_nodes.is_empty() {
931 return Ok(());
932 }
933 for node_id in repass_nodes {
934 cranpose_core::bubble_layout_dirty(applier as &mut dyn Applier, node_id);
935 }
936 applier.get_mut(root)?.mark_needs_layout();
937 Ok(())
938}
939
940struct LayoutBuilder {
941 state: Rc<RefCell<LayoutBuilderState>>,
942}
943
944impl LayoutBuilder {
945 fn new_with_epoch(
946 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
947 epoch: u64,
948 slots: Rc<RefCell<SlotTable>>,
949 frame_arena: FrameLayoutArena,
950 ) -> Self {
951 Self {
952 state: Rc::new(RefCell::new(LayoutBuilderState::new_with_epoch(
953 applier,
954 epoch,
955 slots,
956 frame_arena,
957 ))),
958 }
959 }
960
961 fn measure_node(
962 &mut self,
963 node_id: NodeId,
964 constraints: Constraints,
965 ) -> Result<Rc<MeasuredNode>, NodeError> {
966 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
967 }
968
969 fn set_runtime_handle(&mut self, handle: Option<RuntimeHandle>) {
970 self.state.borrow_mut().runtime_handle = handle;
971 }
972}
973
974impl Drop for LayoutBuilder {
975 fn drop(&mut self) {
976 if Rc::strong_count(&self.state) != 1 {
977 return;
978 }
979 let Ok(mut state) = self.state.try_borrow_mut() else {
980 return;
981 };
982 crate::render_state::replace_layout_frame_arena(std::mem::take(&mut state.frame_arena));
983 }
984}
985
986struct LayoutBuilderState {
987 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
988 runtime_handle: Option<RuntimeHandle>,
989 slots: Rc<RefCell<SlotTable>>,
992 cache_epoch: u64,
993 frame_arena: FrameLayoutArena,
994}
995
996struct LayoutRuntimeFrameBindingCleanup {
997 state: Rc<RefCell<LayoutRuntimeState>>,
998}
999
1000impl LayoutRuntimeFrameBindingCleanup {
1001 fn new(state: Rc<RefCell<LayoutRuntimeState>>) -> Self {
1002 Self { state }
1003 }
1004}
1005
1006impl Drop for LayoutRuntimeFrameBindingCleanup {
1007 fn drop(&mut self) {
1008 self.state.borrow().clear_frame_bindings();
1009 }
1010}
1011
1012impl LayoutBuilderState {
1013 fn new_with_epoch(
1014 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
1015 epoch: u64,
1016 slots: Rc<RefCell<SlotTable>>,
1017 frame_arena: FrameLayoutArena,
1018 ) -> Self {
1019 let runtime_handle = applier.borrow_typed().runtime_handle();
1020
1021 Self {
1022 applier,
1023 runtime_handle,
1024 slots,
1025 cache_epoch: epoch,
1026 frame_arena,
1027 }
1028 }
1029
1030 fn try_with_applier_result<R>(
1031 state_rc: &Rc<RefCell<Self>>,
1032 f: impl FnOnce(&mut MemoryApplier) -> Result<R, NodeError>,
1033 ) -> Option<Result<R, NodeError>> {
1034 let host = {
1035 let state = state_rc.borrow();
1036 Rc::clone(&state.applier)
1037 };
1038
1039 let Ok(mut applier) = host.try_borrow_typed() else {
1041 return None;
1042 };
1043
1044 Some(f(&mut applier))
1045 }
1046
1047 fn with_applier_result<R>(
1048 state_rc: &Rc<RefCell<Self>>,
1049 f: impl FnOnce(&mut MemoryApplier) -> Result<R, NodeError>,
1050 ) -> Result<R, NodeError> {
1051 Self::try_with_applier_result(state_rc, f).unwrap_or_else(|| {
1052 Err(NodeError::MissingContext {
1053 id: NodeId::default(),
1054 reason: "applier already borrowed",
1055 })
1056 })
1057 }
1058
1059 fn clear_node_placed(state_rc: &Rc<RefCell<Self>>, node_id: NodeId) {
1062 let host = {
1063 let state = state_rc.borrow();
1064 Rc::clone(&state.applier)
1065 };
1066 let Ok(mut applier) = host.try_borrow_typed() else {
1067 return;
1068 };
1069 if applier
1071 .with_node::<LayoutNode, _>(node_id, |node| {
1072 node.clear_placed();
1073 })
1074 .is_err()
1075 {
1076 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
1077 node.clear_placed();
1078 });
1079 }
1080 }
1081
1082 fn measure_node(
1083 state_rc: Rc<RefCell<Self>>,
1084 node_id: NodeId,
1085 constraints: Constraints,
1086 ) -> Result<Rc<MeasuredNode>, NodeError> {
1087 Self::clear_node_placed(&state_rc, node_id);
1091
1092 if let Some(subcompose) =
1094 Self::try_measure_subcompose(Rc::clone(&state_rc), node_id, constraints)?
1095 {
1096 return Ok(subcompose);
1097 }
1098
1099 if let Some(result) = Self::try_with_applier_result(&state_rc, |applier| {
1101 match applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1102 LayoutNodeSnapshot::from_layout_node(layout_node)
1103 }) {
1104 Ok(snapshot) => Ok(Some(snapshot)),
1105 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => Ok(None),
1106 Err(err) => Err(err),
1107 }
1108 }) {
1109 if let Some(snapshot) = result? {
1111 return Self::measure_layout_node(
1112 Rc::clone(&state_rc),
1113 node_id,
1114 snapshot,
1115 constraints,
1116 );
1117 }
1118 }
1119 Ok(Rc::new(MeasuredNode::new(
1124 node_id,
1125 Size::default(),
1126 Point { x: 0.0, y: 0.0 },
1127 Point::default(), Vec::new(),
1129 )))
1130 }
1131
1132 fn try_measure_subcompose(
1133 state_rc: Rc<RefCell<Self>>,
1134 node_id: NodeId,
1135 constraints: Constraints,
1136 ) -> Result<Option<Rc<MeasuredNode>>, NodeError> {
1137 let applier_host = {
1138 let state = state_rc.borrow();
1139 Rc::clone(&state.applier)
1140 };
1141
1142 let (node_handle, resolved_modifiers) = {
1143 let Ok(mut applier) = applier_host.try_borrow_typed() else {
1145 return Ok(None);
1146 };
1147 let node = match applier.get_mut(node_id) {
1148 Ok(node) => node,
1149 Err(NodeError::Missing { .. }) => return Ok(None),
1150 Err(err) => return Err(err),
1151 };
1152 let any = node.as_any_mut();
1153 if let Some(subcompose) =
1154 any.downcast_mut::<crate::subcompose_layout::SubcomposeLayoutNode>()
1155 {
1156 let handle = subcompose.handle();
1157 let resolved_modifiers = handle.resolved_modifiers();
1158 (handle, resolved_modifiers)
1159 } else {
1160 return Ok(None);
1161 }
1162 };
1163
1164 let runtime_handle = {
1165 let mut state = state_rc.borrow_mut();
1166 if state.runtime_handle.is_none() {
1167 if let Ok(applier) = applier_host.try_borrow_typed() {
1169 state.runtime_handle = applier.runtime_handle();
1170 }
1171 }
1172 state
1173 .runtime_handle
1174 .clone()
1175 .ok_or(NodeError::MissingContext {
1176 id: node_id,
1177 reason: "runtime handle required for subcomposition",
1178 })?
1179 };
1180
1181 let props = resolved_modifiers.layout_properties();
1182 let padding = resolved_modifiers.padding();
1183 let offset = resolved_modifiers.offset();
1184 let mut inner_constraints = normalize_constraints(subtract_padding(constraints, padding));
1185
1186 if let DimensionConstraint::Points(width) = props.width() {
1187 let constrained_width = width - padding.horizontal_sum();
1188 inner_constraints.max_width = inner_constraints.max_width.min(constrained_width);
1189 inner_constraints.min_width = inner_constraints.min_width.min(constrained_width);
1190 }
1191 if let DimensionConstraint::Points(height) = props.height() {
1192 let constrained_height = height - padding.vertical_sum();
1193 inner_constraints.max_height = inner_constraints.max_height.min(constrained_height);
1194 inner_constraints.min_height = inner_constraints.min_height.min(constrained_height);
1195 }
1196
1197 let mut slots_guard = SlotsGuard::take(Rc::clone(&state_rc));
1198 let slots_host = slots_guard.host();
1199 let applier_host_dyn: Rc<dyn ApplierHost> = applier_host.clone();
1200 let observer = SnapshotStateObserver::new(|callback| callback());
1201 let composer = Composer::new(
1202 Rc::clone(&slots_host),
1203 applier_host_dyn,
1204 runtime_handle.clone(),
1205 observer,
1206 Some(node_id),
1207 );
1208 composer.enter_phase(Phase::Measure);
1209
1210 let state_rc_clone = Rc::clone(&state_rc);
1211 let measure_error = RefCell::new(None);
1212 let state_rc_for_subcompose = Rc::clone(&state_rc_clone);
1213 let error_for_subcompose = &measure_error;
1214 let measured_children = node_handle.measured_children_scratch();
1215 let measured_children_for_subcompose = Rc::clone(&measured_children);
1216
1217 let measure_result = node_handle.measure(
1218 &composer,
1219 node_id,
1220 inner_constraints,
1221 Box::new(
1222 move |child_id: NodeId, child_constraints: Constraints| -> Size {
1223 match Self::measure_node(
1224 Rc::clone(&state_rc_for_subcompose),
1225 child_id,
1226 child_constraints,
1227 ) {
1228 Ok(measured) => {
1229 measured_children_for_subcompose
1230 .borrow_mut()
1231 .insert(child_id, Rc::clone(&measured));
1232 measured.size
1233 }
1234 Err(err) => {
1235 let mut slot = error_for_subcompose.borrow_mut();
1236 if slot.is_none() {
1237 *slot = Some(err);
1238 }
1239 Size::default()
1240 }
1241 }
1242 },
1243 ),
1244 &measure_error,
1245 )?;
1246 drop(composer);
1247 slots_guard.restore(slots_host.into_table()?);
1248
1249 if let Some(err) = measure_error.borrow_mut().take() {
1250 return Err(err);
1251 }
1252
1253 let cranpose_ui_layout::MeasureResult {
1257 size: measured_size,
1258 placements,
1259 } = measure_result;
1260
1261 let mut width = measured_size.width + padding.horizontal_sum();
1262 let mut height = measured_size.height + padding.vertical_sum();
1263
1264 width = resolve_dimension(
1265 width,
1266 props.width(),
1267 props.min_width(),
1268 props.max_width(),
1269 constraints.min_width,
1270 constraints.max_width,
1271 );
1272 height = resolve_dimension(
1273 height,
1274 props.height(),
1275 props.min_height(),
1276 props.max_height(),
1277 constraints.min_height,
1278 constraints.max_height,
1279 );
1280
1281 let mut children = Vec::with_capacity(placements.len());
1282 let mut measured_children_by_id = measured_children.borrow_mut();
1283
1284 if let Ok(mut applier) = applier_host.try_borrow_typed() {
1286 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |parent_node| {
1287 parent_node.set_measured_size(Size { width, height });
1288 parent_node.clear_needs_measure();
1289 parent_node.clear_needs_layout();
1290 });
1291 }
1292
1293 for placement in &placements {
1294 let child = if let Some(measured) = measured_children_by_id.remove(&placement.node_id) {
1295 measured
1296 } else {
1297 Self::measure_node(Rc::clone(&state_rc), placement.node_id, inner_constraints)?
1303 };
1304 let position = Point {
1305 x: padding.left + placement.x,
1306 y: padding.top + placement.y,
1307 };
1308
1309 if let Ok(mut applier) = applier_host.try_borrow_typed() {
1313 let _ = applier.with_node::<LayoutNode, _>(placement.node_id, |node| {
1314 node.set_position(position);
1315 });
1316 }
1317
1318 children.push(MeasuredChild {
1319 node: child,
1320 offset: position,
1321 });
1322 }
1323
1324 node_handle.set_active_children(children.iter().map(|c| c.node.node_id));
1326 node_handle.recycle_placement_scratch(placements);
1327
1328 Ok(Some(Rc::new(MeasuredNode::new(
1329 node_id,
1330 Size { width, height },
1331 offset,
1332 Point::default(), children,
1334 ))))
1335 }
1336 fn measure_through_modifier_chain(
1343 state_rc: &Rc<RefCell<Self>>,
1344 node_id: NodeId,
1345 runtime_state: &mut LayoutRuntimeState,
1346 measure_policy: &Rc<dyn MeasurePolicy>,
1347 constraints: Constraints,
1348 layout_node_data: &mut Vec<LayoutModifierNodeData>,
1349 placements: &mut Vec<Placement>,
1350 ) -> ModifierChainMeasurement {
1351 use cranpose_foundation::NodeCapabilities;
1352
1353 layout_node_data.clear();
1355 let mut offset = Point::default();
1356
1357 {
1358 let state = state_rc.borrow();
1359 let mut applier = state.applier.borrow_typed();
1360
1361 let _ = applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1362 let chain_handle = layout_node.modifier_chain();
1363
1364 if !chain_handle.has_layout_nodes() {
1365 return;
1366 }
1367
1368 chain_handle.chain().for_each_forward_matching(
1370 NodeCapabilities::LAYOUT,
1371 |node_ref| {
1372 if let Some(index) = node_ref.entry_index() {
1373 if let Some(node_rc) = chain_handle.chain().get_node_rc(index) {
1375 layout_node_data.push((index, Rc::clone(&node_rc)));
1376 }
1377
1378 node_ref.with_node(|node| {
1382 if let Some(offset_node) =
1383 node.as_any()
1384 .downcast_ref::<crate::modifier_nodes::OffsetNode>()
1385 {
1386 let delta = offset_node.offset();
1387 offset.x += delta.x;
1388 offset.y += delta.y;
1389 }
1390 });
1391 }
1392 },
1393 );
1394 });
1395 }
1396
1397 if layout_node_data.is_empty() {
1400 let final_size = measure_policy.measure_into(
1401 runtime_state.child_measurables(),
1402 constraints,
1403 placements,
1404 );
1405
1406 return ModifierChainMeasurement {
1407 size: final_size,
1408 content_offset: Point::default(),
1409 offset,
1410 };
1411 }
1412
1413 runtime_state.reconcile_coordinator_chain(layout_node_data.as_slice());
1414 let frame = CoordinatorFrame::new(
1415 measure_policy,
1416 runtime_state.child_measurables(),
1417 placements,
1418 );
1419
1420 let placeable = runtime_state
1422 .coordinator_chain()
1423 .measure_from(0, &frame, constraints);
1424 let final_size = Size {
1425 width: placeable.width(),
1426 height: placeable.height(),
1427 };
1428
1429 let content_offset = placeable.content_offset();
1431 let all_placement_offset = Point {
1432 x: content_offset.0,
1433 y: content_offset.1,
1434 };
1435
1436 let content_offset = Point {
1440 x: all_placement_offset.x - offset.x,
1441 y: all_placement_offset.y - offset.y,
1442 };
1443
1444 let invalidations = frame.take_invalidations();
1448 if !invalidations.is_empty() {
1449 Self::with_applier_result(state_rc, |applier| {
1451 applier.with_node::<LayoutNode, _>(node_id, |layout_node| {
1452 for kind in invalidations {
1453 match kind {
1454 InvalidationKind::Layout => layout_node.mark_needs_measure(),
1455 InvalidationKind::Draw => layout_node.mark_needs_redraw(),
1456 InvalidationKind::Semantics => layout_node.mark_needs_semantics(),
1457 InvalidationKind::PointerInput => layout_node.mark_needs_pointer_pass(),
1458 InvalidationKind::Focus => layout_node.mark_needs_focus_sync(),
1459 }
1460 }
1461 })
1462 })
1463 .ok();
1464 }
1465
1466 ModifierChainMeasurement {
1467 size: final_size,
1468 content_offset,
1469 offset,
1470 }
1471 }
1472
1473 fn layout_child_measure_data(
1474 applier: &mut MemoryApplier,
1475 child_id: NodeId,
1476 ) -> Result<Option<LayoutChildMeasureData>, NodeError> {
1477 match applier.with_node::<LayoutNode, _>(child_id, |n| LayoutChildMeasureData {
1478 cache: n.cache_handles(),
1479 layout_state: Some(n.layout_state_handle()),
1480 needs_layout: n.needs_layout(),
1481 needs_measure: n.needs_measure(),
1482 }) {
1483 Ok(data) => Ok(Some(data)),
1484 Err(NodeError::TypeMismatch { .. }) => {
1485 match applier.with_node::<SubcomposeLayoutNode, _>(child_id, |n| {
1486 LayoutChildMeasureData {
1487 cache: LayoutNodeCacheHandles::default(),
1488 layout_state: None,
1489 needs_layout: n.needs_layout(),
1490 needs_measure: n.needs_measure(),
1491 }
1492 }) {
1493 Ok(data) => Ok(Some(data)),
1494 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {
1495 Ok(None)
1496 }
1497 Err(err) => Err(err),
1498 }
1499 }
1500 Err(NodeError::Missing { .. }) => Ok(None),
1501 Err(err) => Err(err),
1502 }
1503 }
1504
1505 fn measure_layout_node(
1506 state_rc: Rc<RefCell<Self>>,
1507 node_id: NodeId,
1508 snapshot: LayoutNodeSnapshot,
1509 constraints: Constraints,
1510 ) -> Result<Rc<MeasuredNode>, NodeError> {
1511 let cache_epoch = {
1512 let state = state_rc.borrow();
1513 state.cache_epoch
1514 };
1515 let LayoutNodeSnapshot {
1516 measure_policy,
1517 cache,
1518 layout_runtime_state,
1519 needs_layout,
1520 needs_measure,
1521 } = snapshot;
1522 cache.activate(cache_epoch);
1523
1524 if needs_measure {
1525 }
1527
1528 if !needs_measure && !needs_layout {
1532 if let Some(cached) = cache.get_measurement(constraints) {
1534 Self::with_applier_result(&state_rc, |applier| {
1536 applier.with_node::<LayoutNode, _>(node_id, |node| {
1537 node.clear_needs_measure();
1538 node.clear_needs_layout();
1539 })
1540 })
1541 .ok();
1542 return Ok(cached);
1543 }
1544 }
1545
1546 let (runtime_handle, applier_host) = {
1547 let state = state_rc.borrow();
1548 (state.runtime_handle.clone(), Rc::clone(&state.applier))
1549 };
1550
1551 let measure_handle = LayoutMeasureHandle::new(Rc::clone(&state_rc));
1552 let error = Rc::new(RefCell::new(None));
1553 let mut pools = VecPools::acquire(Rc::clone(&state_rc));
1554 let (records, child_ids, layout_node_data, placements) = pools.parts();
1555
1556 applier_host
1557 .borrow_typed()
1558 .with_node::<LayoutNode, _>(node_id, |node| {
1559 child_ids.extend_from_slice(&node.children);
1560 })?;
1561
1562 let mut valid_child_count = 0;
1563 for index in 0..child_ids.len() {
1564 let child_id = child_ids[index];
1565 let child_exists = {
1566 let mut applier = applier_host.borrow_typed();
1567 Self::layout_child_measure_data(&mut applier, child_id)?.is_some()
1568 };
1569 if child_exists {
1570 child_ids[valid_child_count] = child_id;
1571 valid_child_count += 1;
1572 }
1573 }
1574 child_ids.truncate(valid_child_count);
1575
1576 let _frame_binding_cleanup =
1577 LayoutRuntimeFrameBindingCleanup::new(Rc::clone(&layout_runtime_state));
1578
1579 {
1580 let mut runtime_state = layout_runtime_state.borrow_mut();
1581 runtime_state.reconcile_child_measurables(child_ids.as_slice());
1582
1583 for (index, &child_id) in child_ids.iter().enumerate() {
1584 let data = {
1585 let mut applier = applier_host.borrow_typed();
1586 Self::layout_child_measure_data(&mut applier, child_id)?
1587 };
1588 let Some(data) = data else {
1589 continue;
1590 };
1591
1592 let child_state = runtime_state.child_state(index);
1593 child_state.configure(LayoutChildMeasureConfig {
1594 applier: Rc::clone(&applier_host),
1595 node_id: child_id,
1596 error: Rc::clone(&error),
1597 runtime_handle: runtime_handle.clone(),
1598 cache: data.cache,
1599 cache_epoch,
1600 force_remeasure: data.needs_layout || data.needs_measure,
1601 measure_handle: Some(measure_handle.clone()),
1602 layout_state: data.layout_state,
1603 });
1604 records.push((child_id, ChildRecord { state: child_state }));
1605 }
1606 }
1607
1608 let chain_constraints = constraints;
1609
1610 let modifier_chain_result = {
1611 let mut runtime_state = layout_runtime_state.borrow_mut();
1612 Self::measure_through_modifier_chain(
1613 &state_rc,
1614 node_id,
1615 &mut runtime_state,
1616 &measure_policy,
1617 chain_constraints,
1618 layout_node_data,
1619 placements,
1620 )
1621 };
1622
1623 let (width, height, content_offset, offset) = {
1625 let result = modifier_chain_result;
1626 if let Some(err) = error.borrow_mut().take() {
1629 return Err(err);
1630 }
1631
1632 (
1633 result.size.width,
1634 result.size.height,
1635 result.content_offset,
1636 result.offset,
1637 )
1638 };
1639
1640 let mut measured_children = Vec::with_capacity(records.len());
1641 for (child_id, record) in records.iter() {
1642 if let Some(measured) = record.state.take_measured() {
1643 let base_position = placements
1644 .iter()
1645 .find(|placement| placement.node_id == *child_id)
1646 .map(|placement| Point {
1647 x: placement.x,
1648 y: placement.y,
1649 })
1650 .or_else(|| record.state.last_position())
1651 .unwrap_or(Point { x: 0.0, y: 0.0 });
1652 let position = Point {
1654 x: content_offset.x + base_position.x,
1655 y: content_offset.y + base_position.y,
1656 };
1657 measured_children.push(MeasuredChild {
1658 node: measured,
1659 offset: position,
1660 });
1661 }
1662 }
1663
1664 let measured = Rc::new(MeasuredNode::new(
1665 node_id,
1666 Size { width, height },
1667 offset,
1668 content_offset,
1669 measured_children,
1670 ));
1671
1672 cache.store_measurement(constraints, Rc::clone(&measured));
1673
1674 Self::with_applier_result(&state_rc, |applier| {
1676 applier.with_node::<LayoutNode, _>(node_id, |node| {
1677 node.clear_needs_measure();
1678 node.clear_needs_layout();
1679 node.set_measured_size(Size { width, height });
1680 node.set_content_offset(content_offset);
1681 })
1682 })
1683 .ok();
1684
1685 Ok(measured)
1686 }
1687}
1688
1689struct LayoutChildMeasureData {
1690 cache: LayoutNodeCacheHandles,
1691 layout_state: Option<Rc<RefCell<LayoutState>>>,
1692 needs_layout: bool,
1693 needs_measure: bool,
1694}
1695
1696struct LayoutNodeSnapshot {
1703 measure_policy: Rc<dyn MeasurePolicy>,
1704 cache: LayoutNodeCacheHandles,
1705 layout_runtime_state: Rc<RefCell<LayoutRuntimeState>>,
1706 needs_layout: bool,
1707 needs_measure: bool,
1709}
1710
1711impl LayoutNodeSnapshot {
1712 fn from_layout_node(node: &LayoutNode) -> Self {
1713 Self {
1714 measure_policy: Rc::clone(&node.measure_policy),
1715 cache: node.cache_handles(),
1716 layout_runtime_state: node.layout_runtime_state_handle(),
1717 needs_layout: node.needs_layout(),
1718 needs_measure: node.needs_measure(),
1719 }
1720 }
1721}
1722
1723struct VecPools {
1725 state: Rc<RefCell<LayoutBuilderState>>,
1726 records: Vec<(NodeId, ChildRecord)>,
1727 child_ids: Vec<NodeId>,
1728 layout_node_data: Vec<LayoutModifierNodeData>,
1729 placements: Vec<Placement>,
1730}
1731
1732impl VecPools {
1733 fn acquire(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1734 let (records, child_ids, layout_node_data, placements) = {
1735 let mut state_mut = state.borrow_mut();
1736 (
1737 state_mut.frame_arena.tmp_records.acquire(),
1738 state_mut.frame_arena.tmp_child_ids.acquire(),
1739 state_mut.frame_arena.tmp_layout_node_data.acquire(),
1740 state_mut.frame_arena.tmp_placements.acquire(),
1741 )
1742 };
1743 Self {
1744 state,
1745 records,
1746 child_ids,
1747 layout_node_data,
1748 placements,
1749 }
1750 }
1751
1752 #[allow(clippy::type_complexity)] fn parts(
1754 &mut self,
1755 ) -> (
1756 &mut Vec<(NodeId, ChildRecord)>,
1757 &mut Vec<NodeId>,
1758 &mut Vec<LayoutModifierNodeData>,
1759 &mut Vec<Placement>,
1760 ) {
1761 (
1762 &mut self.records,
1763 &mut self.child_ids,
1764 &mut self.layout_node_data,
1765 &mut self.placements,
1766 )
1767 }
1768}
1769
1770impl Drop for VecPools {
1771 fn drop(&mut self) {
1772 let mut state = self.state.borrow_mut();
1773 state
1774 .frame_arena
1775 .tmp_records
1776 .release(std::mem::take(&mut self.records));
1777 state
1778 .frame_arena
1779 .tmp_child_ids
1780 .release(std::mem::take(&mut self.child_ids));
1781 state
1782 .frame_arena
1783 .tmp_layout_node_data
1784 .release(std::mem::take(&mut self.layout_node_data));
1785 state
1786 .frame_arena
1787 .tmp_placements
1788 .release(std::mem::take(&mut self.placements));
1789 }
1790}
1791
1792struct SlotsGuard {
1793 state: Rc<RefCell<LayoutBuilderState>>,
1794 slots: Option<SlotTable>,
1795}
1796
1797impl SlotsGuard {
1798 fn take(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1799 let slots = {
1800 let state_ref = state.borrow();
1801 let mut slots_ref = state_ref.slots.borrow_mut();
1802 std::mem::take(&mut *slots_ref)
1803 };
1804 Self {
1805 state,
1806 slots: Some(slots),
1807 }
1808 }
1809
1810 fn host(&mut self) -> Rc<SlotsHost> {
1811 let slots = self.slots.take().unwrap_or_default();
1812 Rc::new(SlotsHost::new(slots))
1813 }
1814
1815 fn restore(&mut self, slots: SlotTable) {
1816 debug_assert!(self.slots.is_none());
1817 self.slots = Some(slots);
1818 }
1819}
1820
1821impl Drop for SlotsGuard {
1822 fn drop(&mut self) {
1823 if let Some(slots) = self.slots.take() {
1824 let state_ref = self.state.borrow();
1825 *state_ref.slots.borrow_mut() = slots;
1826 }
1827 }
1828}
1829
1830#[derive(Clone)]
1831struct LayoutMeasureHandle {
1832 state: Rc<RefCell<LayoutBuilderState>>,
1833}
1834
1835impl LayoutMeasureHandle {
1836 fn new(state: Rc<RefCell<LayoutBuilderState>>) -> Self {
1837 Self { state }
1838 }
1839
1840 fn measure(
1841 &self,
1842 node_id: NodeId,
1843 constraints: Constraints,
1844 ) -> Result<Rc<MeasuredNode>, NodeError> {
1845 LayoutBuilderState::measure_node(Rc::clone(&self.state), node_id, constraints)
1846 }
1847}
1848
1849#[derive(Debug, Clone)]
1850pub(crate) struct MeasuredNode {
1851 node_id: NodeId,
1852 size: Size,
1853 offset: Point,
1855 content_offset: Point,
1857 children: Vec<MeasuredChild>,
1858}
1859
1860impl MeasuredNode {
1861 fn new(
1862 node_id: NodeId,
1863 size: Size,
1864 offset: Point,
1865 content_offset: Point,
1866 children: Vec<MeasuredChild>,
1867 ) -> Self {
1868 Self {
1869 node_id,
1870 size,
1871 offset,
1872 content_offset,
1873 children,
1874 }
1875 }
1876}
1877
1878#[derive(Debug, Clone)]
1879struct MeasuredChild {
1880 node: Rc<MeasuredNode>,
1881 offset: Point,
1882}
1883
1884struct ChildRecord {
1885 state: Rc<LayoutChildMeasureState>,
1886}
1887
1888struct CoordinatorFrame<'a> {
1889 measure_policy: &'a Rc<dyn MeasurePolicy>,
1890 measurables: &'a [Box<dyn Measurable>],
1891 placements: RefCell<&'a mut Vec<Placement>>,
1892 context: RefCell<LayoutNodeContext>,
1893}
1894
1895impl<'a> CoordinatorFrame<'a> {
1896 fn new(
1897 measure_policy: &'a Rc<dyn MeasurePolicy>,
1898 measurables: &'a [Box<dyn Measurable>],
1899 placements: &'a mut Vec<Placement>,
1900 ) -> Self {
1901 Self {
1902 measure_policy,
1903 measurables,
1904 placements: RefCell::new(placements),
1905 context: RefCell::new(LayoutNodeContext::new()),
1906 }
1907 }
1908
1909 fn take_invalidations(&self) -> Vec<InvalidationKind> {
1910 self.context.borrow_mut().take_invalidations()
1911 }
1912}
1913
1914struct CoordinatorLink<'chain, 'frame_ref, 'frame_data> {
1915 chain: &'chain CoordinatorChain,
1916 frame: &'frame_ref CoordinatorFrame<'frame_data>,
1917 index: usize,
1918}
1919
1920impl Measurable for CoordinatorLink<'_, '_, '_> {
1921 fn measure(&self, constraints: Constraints) -> Placeable {
1922 self.chain.measure_from(self.index, self.frame, constraints)
1923 }
1924
1925 fn min_intrinsic_width(&self, height: f32) -> f32 {
1926 self.chain
1927 .min_intrinsic_width_from(self.index, self.frame, height)
1928 }
1929
1930 fn max_intrinsic_width(&self, height: f32) -> f32 {
1931 self.chain
1932 .max_intrinsic_width_from(self.index, self.frame, height)
1933 }
1934
1935 fn min_intrinsic_height(&self, width: f32) -> f32 {
1936 self.chain
1937 .min_intrinsic_height_from(self.index, self.frame, width)
1938 }
1939
1940 fn max_intrinsic_height(&self, width: f32) -> f32 {
1941 self.chain
1942 .max_intrinsic_height_from(self.index, self.frame, width)
1943 }
1944}
1945
1946struct CoordinatorNode {
1947 modifier_index: usize,
1948 node: Rc<RefCell<Box<dyn cranpose_foundation::ModifierNode>>>,
1949 measured_size: Cell<Size>,
1950 accumulated_offset: Cell<Point>,
1951}
1952
1953impl CoordinatorNode {
1954 fn new(
1955 modifier_index: usize,
1956 node: Rc<RefCell<Box<dyn cranpose_foundation::ModifierNode>>>,
1957 ) -> Self {
1958 Self {
1959 modifier_index,
1960 node,
1961 measured_size: Cell::new(Size::default()),
1962 accumulated_offset: Cell::new(Point::default()),
1963 }
1964 }
1965
1966 fn matches(
1967 &self,
1968 modifier_index: usize,
1969 node: &Rc<RefCell<Box<dyn cranpose_foundation::ModifierNode>>>,
1970 ) -> bool {
1971 self.modifier_index == modifier_index && Rc::ptr_eq(&self.node, node)
1972 }
1973
1974 #[cfg(test)]
1975 fn ptr(&self) -> usize {
1976 Rc::as_ptr(&self.node) as *const () as usize
1977 }
1978}
1979
1980#[derive(Default)]
1981struct CoordinatorChain {
1982 nodes: Vec<CoordinatorNode>,
1983}
1984
1985impl CoordinatorChain {
1986 fn reconcile(&mut self, layout_node_data: &[LayoutModifierNodeData]) {
1987 if self.matches(layout_node_data) {
1988 return;
1989 }
1990
1991 let mut previous_nodes = std::mem::take(&mut self.nodes);
1992 self.nodes.reserve(layout_node_data.len());
1993
1994 for (modifier_index, node) in layout_node_data.iter() {
1995 if let Some(position) = previous_nodes
1996 .iter()
1997 .position(|candidate| candidate.matches(*modifier_index, node))
1998 {
1999 self.nodes.push(previous_nodes.swap_remove(position));
2000 } else {
2001 self.nodes
2002 .push(CoordinatorNode::new(*modifier_index, Rc::clone(node)));
2003 }
2004 }
2005 }
2006
2007 fn matches(&self, layout_node_data: &[LayoutModifierNodeData]) -> bool {
2008 self.nodes.len() == layout_node_data.len()
2009 && self
2010 .nodes
2011 .iter()
2012 .zip(layout_node_data.iter())
2013 .all(|(node, (modifier_index, node_rc))| node.matches(*modifier_index, node_rc))
2014 }
2015
2016 fn measure_from(
2017 &self,
2018 index: usize,
2019 frame: &CoordinatorFrame<'_>,
2020 constraints: Constraints,
2021 ) -> Placeable {
2022 let Some(node) = self.nodes.get(index) else {
2023 let mut placements = frame.placements.borrow_mut();
2024 let size =
2025 frame
2026 .measure_policy
2027 .measure_into(frame.measurables, constraints, &mut placements);
2028 return Placeable::value(size.width, size.height, NodeId::default());
2029 };
2030
2031 let wrapped = CoordinatorLink {
2032 chain: self,
2033 frame,
2034 index: index + 1,
2035 };
2036 let node_borrow = node.node.borrow();
2037
2038 let Some(layout_node) = node_borrow.as_layout_node() else {
2039 let placeable = wrapped.measure(constraints);
2040 let child_accumulated = self.total_content_offset_from(index + 1);
2041 node.accumulated_offset.set(child_accumulated);
2042 return Placeable::value_with_offset(
2043 placeable.width(),
2044 placeable.height(),
2045 NodeId::default(),
2046 (child_accumulated.x, child_accumulated.y),
2047 );
2048 };
2049
2050 let result = match frame.context.try_borrow_mut() {
2051 Ok(mut context) => layout_node.measure(&mut *context, &wrapped, constraints),
2052 Err(_) => {
2053 let mut temp = LayoutNodeContext::new();
2054 let result = layout_node.measure(&mut temp, &wrapped, constraints);
2055 if let Ok(mut context) = frame.context.try_borrow_mut() {
2056 for kind in temp.take_invalidations() {
2057 context.invalidate(kind);
2058 }
2059 }
2060 result
2061 }
2062 };
2063
2064 node.measured_size.set(result.size);
2065 let local_offset = Point {
2066 x: result.placement_offset_x,
2067 y: result.placement_offset_y,
2068 };
2069 let child_accumulated = self.total_content_offset_from(index + 1);
2070 let accumulated = Point {
2071 x: local_offset.x + child_accumulated.x,
2072 y: local_offset.y + child_accumulated.y,
2073 };
2074 node.accumulated_offset.set(accumulated);
2075
2076 Placeable::value_with_offset(
2077 result.size.width,
2078 result.size.height,
2079 NodeId::default(),
2080 (accumulated.x, accumulated.y),
2081 )
2082 }
2083
2084 fn min_intrinsic_width_from(
2085 &self,
2086 index: usize,
2087 frame: &CoordinatorFrame<'_>,
2088 height: f32,
2089 ) -> f32 {
2090 let Some(node) = self.nodes.get(index) else {
2091 return frame
2092 .measure_policy
2093 .min_intrinsic_width(frame.measurables, height);
2094 };
2095 let wrapped = CoordinatorLink {
2096 chain: self,
2097 frame,
2098 index: index + 1,
2099 };
2100 let node_borrow = node.node.borrow();
2101 node_borrow
2102 .as_layout_node()
2103 .map(|layout_node| layout_node.min_intrinsic_width(&wrapped, height))
2104 .unwrap_or_else(|| wrapped.min_intrinsic_width(height))
2105 }
2106
2107 fn max_intrinsic_width_from(
2108 &self,
2109 index: usize,
2110 frame: &CoordinatorFrame<'_>,
2111 height: f32,
2112 ) -> f32 {
2113 let Some(node) = self.nodes.get(index) else {
2114 return frame
2115 .measure_policy
2116 .max_intrinsic_width(frame.measurables, height);
2117 };
2118 let wrapped = CoordinatorLink {
2119 chain: self,
2120 frame,
2121 index: index + 1,
2122 };
2123 let node_borrow = node.node.borrow();
2124 node_borrow
2125 .as_layout_node()
2126 .map(|layout_node| layout_node.max_intrinsic_width(&wrapped, height))
2127 .unwrap_or_else(|| wrapped.max_intrinsic_width(height))
2128 }
2129
2130 fn min_intrinsic_height_from(
2131 &self,
2132 index: usize,
2133 frame: &CoordinatorFrame<'_>,
2134 width: f32,
2135 ) -> f32 {
2136 let Some(node) = self.nodes.get(index) else {
2137 return frame
2138 .measure_policy
2139 .min_intrinsic_height(frame.measurables, width);
2140 };
2141 let wrapped = CoordinatorLink {
2142 chain: self,
2143 frame,
2144 index: index + 1,
2145 };
2146 let node_borrow = node.node.borrow();
2147 node_borrow
2148 .as_layout_node()
2149 .map(|layout_node| layout_node.min_intrinsic_height(&wrapped, width))
2150 .unwrap_or_else(|| wrapped.min_intrinsic_height(width))
2151 }
2152
2153 fn max_intrinsic_height_from(
2154 &self,
2155 index: usize,
2156 frame: &CoordinatorFrame<'_>,
2157 width: f32,
2158 ) -> f32 {
2159 let Some(node) = self.nodes.get(index) else {
2160 return frame
2161 .measure_policy
2162 .max_intrinsic_height(frame.measurables, width);
2163 };
2164 let wrapped = CoordinatorLink {
2165 chain: self,
2166 frame,
2167 index: index + 1,
2168 };
2169 let node_borrow = node.node.borrow();
2170 node_borrow
2171 .as_layout_node()
2172 .map(|layout_node| layout_node.max_intrinsic_height(&wrapped, width))
2173 .unwrap_or_else(|| wrapped.max_intrinsic_height(width))
2174 }
2175
2176 fn total_content_offset_from(&self, index: usize) -> Point {
2177 self.nodes
2178 .get(index)
2179 .map(|node| node.accumulated_offset.get())
2180 .unwrap_or_default()
2181 }
2182
2183 #[cfg(test)]
2184 fn debug_ptrs(&self) -> Vec<usize> {
2185 self.nodes.iter().map(CoordinatorNode::ptr).collect()
2186 }
2187}
2188
2189#[derive(Default)]
2190pub(crate) struct LayoutRuntimeState {
2191 child_ids: Vec<NodeId>,
2192 child_states: Vec<Rc<LayoutChildMeasureState>>,
2193 child_measurables: Vec<Box<dyn Measurable>>,
2194 coordinator_chain: CoordinatorChain,
2195}
2196
2197impl LayoutRuntimeState {
2198 fn reconcile_child_measurables(&mut self, child_ids: &[NodeId]) {
2199 if self.child_ids == child_ids {
2200 return;
2201 }
2202
2203 let mut previous_ids = std::mem::take(&mut self.child_ids);
2204 let mut previous_states = std::mem::take(&mut self.child_states);
2205 let mut previous_measurables = std::mem::take(&mut self.child_measurables);
2206
2207 self.child_ids.reserve(child_ids.len());
2208 self.child_states.reserve(child_ids.len());
2209 self.child_measurables.reserve(child_ids.len());
2210
2211 for &child_id in child_ids {
2212 if let Some(position) = previous_ids.iter().position(|&id| id == child_id) {
2213 self.child_ids.push(previous_ids.swap_remove(position));
2214 self.child_states
2215 .push(previous_states.swap_remove(position));
2216 self.child_measurables
2217 .push(previous_measurables.swap_remove(position));
2218 } else {
2219 let state = LayoutChildMeasureState::new(child_id);
2220 self.child_ids.push(child_id);
2221 self.child_states.push(Rc::clone(&state));
2222 self.child_measurables
2223 .push(Box::new(LayoutChildMeasurable::new(state)));
2224 }
2225 }
2226 }
2227
2228 fn child_state(&self, index: usize) -> Rc<LayoutChildMeasureState> {
2229 Rc::clone(&self.child_states[index])
2230 }
2231
2232 fn child_measurables(&self) -> &[Box<dyn Measurable>] {
2233 self.child_measurables.as_slice()
2234 }
2235
2236 fn reconcile_coordinator_chain(&mut self, layout_node_data: &[LayoutModifierNodeData]) {
2237 self.coordinator_chain.reconcile(layout_node_data);
2238 }
2239
2240 fn coordinator_chain(&self) -> &CoordinatorChain {
2241 &self.coordinator_chain
2242 }
2243
2244 fn clear_frame_bindings(&self) {
2245 for child_state in &self.child_states {
2246 child_state.clear_frame_bindings();
2247 }
2248 }
2249
2250 #[cfg(test)]
2251 pub(crate) fn debug_stats(&self) -> LayoutRuntimeDebugStats {
2252 LayoutRuntimeDebugStats {
2253 child_ids: self.child_ids.clone(),
2254 child_state_ptrs: self
2255 .child_states
2256 .iter()
2257 .map(|state| Rc::as_ptr(state) as *const () as usize)
2258 .collect(),
2259 child_measurable_ptrs: self
2260 .child_measurables
2261 .iter()
2262 .map(|measurable| {
2263 measurable.as_ref() as *const dyn Measurable as *const () as usize
2264 })
2265 .collect(),
2266 child_measurable_count: self.child_measurables.len(),
2267 coordinator_node_ptrs: self.coordinator_chain.debug_ptrs(),
2268 coordinator_node_count: self.coordinator_chain.nodes.len(),
2269 }
2270 }
2271}
2272
2273#[cfg(test)]
2274#[derive(Debug, Clone, PartialEq, Eq)]
2275pub(crate) struct LayoutRuntimeDebugStats {
2276 pub(crate) child_ids: Vec<NodeId>,
2277 pub(crate) child_state_ptrs: Vec<usize>,
2278 pub(crate) child_measurable_ptrs: Vec<usize>,
2279 pub(crate) child_measurable_count: usize,
2280 pub(crate) coordinator_node_ptrs: Vec<usize>,
2281 pub(crate) coordinator_node_count: usize,
2282}
2283
2284struct LayoutChildMeasureConfig {
2285 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
2286 node_id: NodeId,
2287 error: Rc<RefCell<Option<NodeError>>>,
2288 runtime_handle: Option<RuntimeHandle>,
2289 cache: LayoutNodeCacheHandles,
2290 cache_epoch: u64,
2291 force_remeasure: bool,
2292 measure_handle: Option<LayoutMeasureHandle>,
2293 layout_state: Option<Rc<RefCell<LayoutState>>>,
2294}
2295
2296struct LayoutChildMeasureState {
2297 applier: RefCell<Option<Rc<ConcreteApplierHost<MemoryApplier>>>>,
2298 node_id: Cell<NodeId>,
2299 measured: RefCell<Option<Rc<MeasuredNode>>>,
2300 last_position: Cell<Option<Point>>,
2301 error: RefCell<Option<Rc<RefCell<Option<NodeError>>>>>,
2302 runtime_handle: RefCell<Option<RuntimeHandle>>,
2303 cache: RefCell<LayoutNodeCacheHandles>,
2304 cache_epoch: Cell<u64>,
2305 force_remeasure: Cell<bool>,
2306 measure_handle: RefCell<Option<LayoutMeasureHandle>>,
2307 layout_state: RefCell<Option<Rc<RefCell<LayoutState>>>>,
2308}
2309
2310impl LayoutChildMeasureState {
2311 fn new(node_id: NodeId) -> Rc<Self> {
2312 Rc::new(Self {
2313 applier: RefCell::new(None),
2314 node_id: Cell::new(node_id),
2315 measured: RefCell::new(None),
2316 last_position: Cell::new(None),
2317 error: RefCell::new(None),
2318 runtime_handle: RefCell::new(None),
2319 cache: RefCell::new(LayoutNodeCacheHandles::default()),
2320 cache_epoch: Cell::new(0),
2321 force_remeasure: Cell::new(true),
2322 measure_handle: RefCell::new(None),
2323 layout_state: RefCell::new(None),
2324 })
2325 }
2326
2327 fn configure(&self, config: LayoutChildMeasureConfig) {
2328 config.cache.activate(config.cache_epoch);
2329 *self.applier.borrow_mut() = Some(config.applier);
2330 self.node_id.set(config.node_id);
2331 self.measured.borrow_mut().take();
2332 self.last_position.set(None);
2333 *self.error.borrow_mut() = Some(config.error);
2334 *self.runtime_handle.borrow_mut() = config.runtime_handle;
2335 *self.cache.borrow_mut() = config.cache;
2336 self.cache_epoch.set(config.cache_epoch);
2337 self.force_remeasure.set(config.force_remeasure);
2338 *self.measure_handle.borrow_mut() = config.measure_handle;
2339 *self.layout_state.borrow_mut() = config.layout_state;
2340 }
2341
2342 fn clear_frame_bindings(&self) {
2343 self.measured.borrow_mut().take();
2344 *self.applier.borrow_mut() = None;
2345 *self.error.borrow_mut() = None;
2346 *self.runtime_handle.borrow_mut() = None;
2347 *self.measure_handle.borrow_mut() = None;
2348 *self.layout_state.borrow_mut() = None;
2349 }
2350
2351 fn node_id(&self) -> NodeId {
2352 self.node_id.get()
2353 }
2354
2355 fn cache(&self) -> LayoutNodeCacheHandles {
2356 self.cache.borrow().clone()
2357 }
2358
2359 fn applier(&self) -> Option<Rc<ConcreteApplierHost<MemoryApplier>>> {
2360 self.applier.borrow().clone()
2361 }
2362
2363 fn layout_state(&self) -> Option<Rc<RefCell<LayoutState>>> {
2364 self.layout_state.borrow().clone()
2365 }
2366
2367 fn take_measured(&self) -> Option<Rc<MeasuredNode>> {
2368 self.measured.borrow_mut().take()
2369 }
2370
2371 fn last_position(&self) -> Option<Point> {
2372 self.last_position.get()
2373 }
2374
2375 fn set_last_position(&self, position: Point) {
2376 self.last_position.set(Some(position));
2377 }
2378
2379 fn set_measured(&self, measured: Option<Rc<MeasuredNode>>) {
2380 *self.measured.borrow_mut() = measured;
2381 }
2382
2383 fn record_error(&self, err: NodeError) {
2384 let Some(error) = self.error.borrow().clone() else {
2385 return;
2386 };
2387 let mut slot = error.borrow_mut();
2388 if slot.is_none() {
2389 *slot = Some(err);
2390 }
2391 }
2392
2393 fn perform_measure(&self, constraints: Constraints) -> Result<Rc<MeasuredNode>, NodeError> {
2394 let node_id = self.node_id();
2395 if let Some(handle) = self.measure_handle.borrow().clone() {
2396 return handle.measure(node_id, constraints);
2397 }
2398 let applier = self.applier().ok_or(NodeError::MissingContext {
2399 id: node_id,
2400 reason: "layout child applier not configured",
2401 })?;
2402 measure_node_with_host(
2403 applier,
2404 self.runtime_handle.borrow().clone(),
2405 node_id,
2406 constraints,
2407 self.cache_epoch.get(),
2408 )
2409 }
2410
2411 fn intrinsic_measure(&self, constraints: Constraints) -> Option<Rc<MeasuredNode>> {
2412 let cache = self.cache();
2413 cache.activate(self.cache_epoch.get());
2414 if !self.force_remeasure.get() {
2415 if let Some(cached) = cache.get_measurement(constraints) {
2416 return Some(cached);
2417 }
2418 }
2419
2420 match self.perform_measure(constraints) {
2421 Ok(measured) => {
2422 self.force_remeasure.set(false);
2423 cache.store_measurement(constraints, Rc::clone(&measured));
2424 Some(measured)
2425 }
2426 Err(err) => {
2427 self.record_error(err);
2428 None
2429 }
2430 }
2431 }
2432}
2433
2434struct LayoutChildMeasurable {
2435 state: Rc<LayoutChildMeasureState>,
2436}
2437
2438impl LayoutChildMeasurable {
2439 fn new(state: Rc<LayoutChildMeasureState>) -> Self {
2440 Self { state }
2441 }
2442}
2443
2444impl Measurable for LayoutChildMeasurable {
2445 fn measure(&self, constraints: Constraints) -> Placeable {
2446 let state = &self.state;
2447 let cache = state.cache();
2448 cache.activate(state.cache_epoch.get());
2449 let measured_size;
2450 if !state.force_remeasure.get() {
2451 if let Some(cached) = cache.get_measurement(constraints) {
2452 measured_size = cached.size;
2453 state.set_measured(Some(Rc::clone(&cached)));
2454 } else {
2455 match state.perform_measure(constraints) {
2456 Ok(measured) => {
2457 state.force_remeasure.set(false);
2458 measured_size = measured.size;
2459 cache.store_measurement(constraints, Rc::clone(&measured));
2460 state.set_measured(Some(measured));
2461 }
2462 Err(err) => {
2463 state.record_error(err);
2464 state.set_measured(None);
2465 measured_size = Size {
2466 width: 0.0,
2467 height: 0.0,
2468 };
2469 }
2470 }
2471 }
2472 } else {
2473 match state.perform_measure(constraints) {
2474 Ok(measured) => {
2475 state.force_remeasure.set(false);
2476 measured_size = measured.size;
2477 cache.store_measurement(constraints, Rc::clone(&measured));
2478 state.set_measured(Some(measured));
2479 }
2480 Err(err) => {
2481 state.record_error(err);
2482 state.set_measured(None);
2483 measured_size = Size {
2484 width: 0.0,
2485 height: 0.0,
2486 };
2487 }
2488 }
2489 }
2490
2491 if let Some(layout_state) = state.layout_state() {
2492 let mut layout_state = layout_state.borrow_mut();
2493 layout_state.size = measured_size;
2494 layout_state.measurement_constraints = constraints;
2495 } else if let Some(applier) = state.applier() {
2496 let Ok(mut applier) = applier.try_borrow_typed() else {
2497 return Placeable::value(
2498 measured_size.width,
2499 measured_size.height,
2500 state.node_id(),
2501 );
2502 };
2503 let _ = applier.with_node::<LayoutNode, _>(state.node_id(), |node| {
2504 node.set_measured_size(measured_size);
2505 node.set_measurement_constraints(constraints);
2506 });
2507 }
2508
2509 let state = Rc::clone(&self.state);
2510 let applier = state.applier();
2511 let node_id = state.node_id();
2512 let layout_state = state.layout_state();
2513
2514 let place_fn = Rc::new(move |x: f32, y: f32| {
2515 let internal_offset = state
2516 .measured
2517 .borrow()
2518 .as_ref()
2519 .map(|m| m.offset)
2520 .unwrap_or_default();
2521
2522 let position = Point {
2523 x: x + internal_offset.x,
2524 y: y + internal_offset.y,
2525 };
2526 state.set_last_position(position);
2527
2528 if let Some(layout_state) = &layout_state {
2529 let mut layout_state = layout_state.borrow_mut();
2530 layout_state.position = position;
2531 layout_state.is_placed = true;
2532 } else if let Some(applier) = &applier {
2533 let Ok(mut applier) = applier.try_borrow_typed() else {
2534 return;
2535 };
2536 if applier
2537 .with_node::<LayoutNode, _>(node_id, |node| {
2538 node.set_position(position);
2539 })
2540 .is_err()
2541 {
2542 let _ = applier.with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
2543 node.set_position(position);
2544 });
2545 }
2546 }
2547 });
2548
2549 Placeable::with_place_fn(measured_size.width, measured_size.height, node_id, place_fn)
2550 }
2551
2552 fn min_intrinsic_width(&self, height: f32) -> f32 {
2553 let kind = IntrinsicKind::MinWidth(height);
2554 let cache = self.state.cache();
2555 cache.activate(self.state.cache_epoch.get());
2556 if !self.state.force_remeasure.get() {
2557 if let Some(value) = cache.get_intrinsic(&kind) {
2558 return value;
2559 }
2560 }
2561 let constraints = Constraints {
2562 min_width: 0.0,
2563 max_width: f32::INFINITY,
2564 min_height: height,
2565 max_height: height,
2566 };
2567 if let Some(node) = self.state.intrinsic_measure(constraints) {
2568 let value = node.size.width;
2569 cache.store_intrinsic(kind, value);
2570 value
2571 } else {
2572 0.0
2573 }
2574 }
2575
2576 fn max_intrinsic_width(&self, height: f32) -> f32 {
2577 let kind = IntrinsicKind::MaxWidth(height);
2578 let cache = self.state.cache();
2579 cache.activate(self.state.cache_epoch.get());
2580 if !self.state.force_remeasure.get() {
2581 if let Some(value) = cache.get_intrinsic(&kind) {
2582 return value;
2583 }
2584 }
2585 let constraints = Constraints {
2586 min_width: 0.0,
2587 max_width: f32::INFINITY,
2588 min_height: 0.0,
2589 max_height: height,
2590 };
2591 if let Some(node) = self.state.intrinsic_measure(constraints) {
2592 let value = node.size.width;
2593 cache.store_intrinsic(kind, value);
2594 value
2595 } else {
2596 0.0
2597 }
2598 }
2599
2600 fn min_intrinsic_height(&self, width: f32) -> f32 {
2601 let kind = IntrinsicKind::MinHeight(width);
2602 let cache = self.state.cache();
2603 cache.activate(self.state.cache_epoch.get());
2604 if !self.state.force_remeasure.get() {
2605 if let Some(value) = cache.get_intrinsic(&kind) {
2606 return value;
2607 }
2608 }
2609 let constraints = Constraints {
2610 min_width: width,
2611 max_width: width,
2612 min_height: 0.0,
2613 max_height: f32::INFINITY,
2614 };
2615 if let Some(node) = self.state.intrinsic_measure(constraints) {
2616 let value = node.size.height;
2617 cache.store_intrinsic(kind, value);
2618 value
2619 } else {
2620 0.0
2621 }
2622 }
2623
2624 fn max_intrinsic_height(&self, width: f32) -> f32 {
2625 let kind = IntrinsicKind::MaxHeight(width);
2626 let cache = self.state.cache();
2627 cache.activate(self.state.cache_epoch.get());
2628 if !self.state.force_remeasure.get() {
2629 if let Some(value) = cache.get_intrinsic(&kind) {
2630 return value;
2631 }
2632 }
2633 let constraints = Constraints {
2634 min_width: 0.0,
2635 max_width: width,
2636 min_height: 0.0,
2637 max_height: f32::INFINITY,
2638 };
2639 if let Some(node) = self.state.intrinsic_measure(constraints) {
2640 let value = node.size.height;
2641 cache.store_intrinsic(kind, value);
2642 value
2643 } else {
2644 0.0
2645 }
2646 }
2647
2648 fn flex_parent_data(&self) -> Option<cranpose_ui_layout::FlexParentData> {
2649 let applier = self.state.applier()?;
2650 let node_id = self.state.node_id();
2651 let Ok(mut applier) = applier.try_borrow_typed() else {
2652 return None;
2653 };
2654
2655 applier
2656 .with_node::<LayoutNode, _>(node_id, |layout_node| {
2657 let props = layout_node.resolved_modifiers().layout_properties();
2658 props.weight().map(|weight_data| {
2659 cranpose_ui_layout::FlexParentData::new(weight_data.weight, weight_data.fill)
2660 })
2661 })
2662 .ok()
2663 .flatten()
2664 }
2665}
2666
2667fn measure_node_with_host(
2668 applier: Rc<ConcreteApplierHost<MemoryApplier>>,
2669 runtime_handle: Option<RuntimeHandle>,
2670 node_id: NodeId,
2671 constraints: Constraints,
2672 epoch: u64,
2673) -> Result<Rc<MeasuredNode>, NodeError> {
2674 let runtime_handle = match runtime_handle {
2675 Some(handle) => Some(handle),
2676 None => applier.borrow_typed().runtime_handle(),
2677 };
2678 let mut builder = LayoutBuilder::new_with_epoch(
2679 applier,
2680 epoch,
2681 Rc::new(RefCell::new(SlotTable::default())),
2682 FrameLayoutArena::default(),
2683 );
2684 builder.set_runtime_handle(runtime_handle);
2685 builder.measure_node(node_id, constraints)
2686}
2687
2688#[derive(Clone)]
2689struct RuntimeNodeMetadata {
2690 modifier: Modifier,
2691 resolved_modifiers: ResolvedModifiers,
2692 modifier_slices: Rc<ModifierNodeSlices>,
2693 role: SemanticsRole,
2694 button_handler: Option<Rc<RefCell<dyn FnMut()>>>,
2695}
2696
2697impl Default for RuntimeNodeMetadata {
2698 fn default() -> Self {
2699 Self {
2700 modifier: Modifier::empty(),
2701 resolved_modifiers: ResolvedModifiers::default(),
2702 modifier_slices: Rc::default(),
2703 role: SemanticsRole::Unknown,
2704 button_handler: None,
2705 }
2706 }
2707}
2708
2709fn role_from_modifier_slices(modifier_slices: &ModifierNodeSlices) -> SemanticsRole {
2710 modifier_slices
2711 .text_content()
2712 .map(|text| SemanticsRole::Text {
2713 value: text.to_string(),
2714 })
2715 .unwrap_or(SemanticsRole::Layout)
2716}
2717
2718fn runtime_metadata_for(
2719 applier: &mut MemoryApplier,
2720 node_id: NodeId,
2721) -> Result<RuntimeNodeMetadata, NodeError> {
2722 if let Ok(meta) = applier.with_node::<LayoutNode, _>(node_id, |layout| {
2727 let modifier = layout.modifier.clone();
2728 let resolved_modifiers = layout.resolved_modifiers();
2729 let modifier_slices = layout.modifier_slices_snapshot();
2730 let role = role_from_modifier_slices(&modifier_slices);
2731
2732 RuntimeNodeMetadata {
2733 modifier,
2734 resolved_modifiers,
2735 modifier_slices,
2736 role,
2737 button_handler: None,
2738 }
2739 }) {
2740 return Ok(meta);
2741 }
2742
2743 if let Ok((modifier, resolved_modifiers, modifier_slices)) = applier
2745 .with_node::<SubcomposeLayoutNode, _>(node_id, |node| {
2746 (
2747 node.modifier(),
2748 node.resolved_modifiers(),
2749 node.modifier_slices_snapshot(),
2750 )
2751 })
2752 {
2753 return Ok(RuntimeNodeMetadata {
2754 modifier,
2755 resolved_modifiers,
2756 modifier_slices,
2757 role: SemanticsRole::Subcompose,
2758 button_handler: None,
2759 });
2760 }
2761 Ok(RuntimeNodeMetadata::default())
2762}
2763
2764fn clear_semantics_dirty_flags(
2765 applier: &mut MemoryApplier,
2766 node: &MeasuredNode,
2767) -> Result<(), NodeError> {
2768 match applier.with_node::<LayoutNode, _>(node.node_id, |layout| {
2769 layout.clear_needs_semantics();
2770 }) {
2771 Ok(()) => {}
2772 Err(NodeError::Missing { .. }) => {}
2773 Err(NodeError::TypeMismatch { .. }) => {
2774 match applier.with_node::<SubcomposeLayoutNode, _>(node.node_id, |subcompose| {
2775 subcompose.clear_needs_semantics();
2776 }) {
2777 Ok(()) | Err(NodeError::Missing { .. }) | Err(NodeError::TypeMismatch { .. }) => {}
2778 Err(err) => return Err(err),
2779 }
2780 }
2781 Err(err) => return Err(err),
2782 }
2783
2784 for child in &node.children {
2785 clear_semantics_dirty_flags(applier, &child.node)?;
2786 }
2787
2788 Ok(())
2789}
2790
2791fn build_semantics_tree_from_live_nodes(
2792 applier: &mut MemoryApplier,
2793 node: &MeasuredNode,
2794) -> Result<SemanticsTree, NodeError> {
2795 Ok(SemanticsTree::new(build_semantics_node_from_live_nodes(
2796 applier, node,
2797 )?))
2798}
2799
2800fn semantics_node_from_parts(
2801 node_id: NodeId,
2802 mut role: SemanticsRole,
2803 config: Option<SemanticsConfiguration>,
2804 children: Vec<SemanticsNode>,
2805) -> SemanticsNode {
2806 let mut actions = Vec::new();
2807 let mut description = None;
2808 let mut editable_text = false;
2809 let mut text_selection = None;
2810
2811 if let Some(config) = config {
2812 if config.is_button {
2813 role = SemanticsRole::Button;
2814 }
2815 if config.is_clickable {
2816 actions.push(SemanticsAction::Click {
2817 handler: SemanticsCallback::new(node_id),
2818 });
2819 }
2820 description = config.content_description;
2821 editable_text = config.is_editable_text;
2822 text_selection = config.text_selection;
2823 }
2824
2825 SemanticsNode::new(
2826 node_id,
2827 role,
2828 actions,
2829 children,
2830 description,
2831 editable_text,
2832 text_selection,
2833 )
2834}
2835
2836fn build_semantics_node_from_live_nodes(
2837 applier: &mut MemoryApplier,
2838 node: &MeasuredNode,
2839) -> Result<SemanticsNode, NodeError> {
2840 let (role, config) = match applier.with_node::<LayoutNode, _>(node.node_id, |layout| {
2841 let role = role_from_modifier_slices(&layout.modifier_slices_snapshot());
2842 let config = layout.semantics_configuration();
2843 layout.clear_needs_semantics();
2844 (role, config)
2845 }) {
2846 Ok(data) => data,
2847 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {
2848 match applier.with_node::<SubcomposeLayoutNode, _>(node.node_id, |subcompose| {
2849 subcompose.clear_needs_semantics();
2850 (
2851 SemanticsRole::Subcompose,
2852 collect_semantics_from_modifier(&subcompose.modifier()),
2853 )
2854 }) {
2855 Ok(data) => data,
2856 Err(NodeError::TypeMismatch { .. }) | Err(NodeError::Missing { .. }) => {
2857 (SemanticsRole::Unknown, None)
2858 }
2859 Err(err) => return Err(err),
2860 }
2861 }
2862 Err(err) => return Err(err),
2863 };
2864
2865 let mut children = Vec::with_capacity(node.children.len());
2866 for child in &node.children {
2867 children.push(build_semantics_node_from_live_nodes(applier, &child.node)?);
2868 }
2869
2870 Ok(semantics_node_from_parts(
2871 node.node_id,
2872 role,
2873 config,
2874 children,
2875 ))
2876}
2877
2878fn record_semantics_allocation_stats(node: &SemanticsNode, stats: &mut LayoutAllocationDebugStats) {
2879 stats.semantics_node_count += 1;
2880 stats.semantics_action_count += node.actions.len();
2881 stats.semantics_action_capacity += node.actions.capacity();
2882 stats.semantics_child_count += node.children.len();
2883 stats.semantics_child_capacity += node.children.capacity();
2884 stats.semantics_heap_bytes += node.actions.capacity() * size_of::<SemanticsAction>();
2885 stats.semantics_heap_bytes += node.children.capacity() * size_of::<SemanticsNode>();
2886
2887 if let Some(description) = &node.description {
2888 stats.semantics_description_count += 1;
2889 stats.semantics_description_bytes += description.capacity();
2890 stats.semantics_heap_bytes += description.capacity();
2891 }
2892 if let SemanticsRole::Text { value } = &node.role {
2893 stats.semantics_text_role_bytes += value.capacity();
2894 stats.semantics_heap_bytes += value.capacity();
2895 }
2896
2897 for child in &node.children {
2898 record_semantics_allocation_stats(child, stats);
2899 }
2900}
2901
2902fn record_layout_box_allocation_stats(
2903 layout_box: &LayoutBox,
2904 stats: &mut LayoutAllocationDebugStats,
2905) {
2906 stats.layout_box_count += 1;
2907 stats.layout_box_child_count += layout_box.children.len();
2908 stats.layout_box_child_capacity += layout_box.children.capacity();
2909 stats.layout_box_heap_bytes += layout_box.children.capacity() * size_of::<LayoutBox>();
2910 stats.add_modifier_slice(layout_box.node_data.modifier_slices().debug_stats());
2911
2912 for child in &layout_box.children {
2913 record_layout_box_allocation_stats(child, stats);
2914 }
2915}
2916
2917fn build_layout_tree(
2918 applier: &mut MemoryApplier,
2919 node: &MeasuredNode,
2920) -> Result<LayoutTree, NodeError> {
2921 fn place(
2922 applier: &mut MemoryApplier,
2923 node: &MeasuredNode,
2924 origin: Point,
2925 ) -> Result<LayoutBox, NodeError> {
2926 let top_left = Point {
2928 x: origin.x + node.offset.x,
2929 y: origin.y + node.offset.y,
2930 };
2931 let rect = GeometryRect {
2932 x: top_left.x,
2933 y: top_left.y,
2934 width: node.size.width,
2935 height: node.size.height,
2936 };
2937 let info = runtime_metadata_for(applier, node.node_id)?;
2938 let kind = layout_kind_from_metadata(node.node_id, &info);
2939 let RuntimeNodeMetadata {
2940 modifier,
2941 resolved_modifiers,
2942 modifier_slices,
2943 ..
2944 } = info;
2945 let data = LayoutNodeData::new(modifier, resolved_modifiers, modifier_slices, kind);
2946 let mut children = Vec::with_capacity(node.children.len());
2947 for child in &node.children {
2948 let child_origin = Point {
2949 x: top_left.x + child.offset.x,
2950 y: top_left.y + child.offset.y,
2951 };
2952 children.push(place(applier, &child.node, child_origin)?);
2953 }
2954 Ok(LayoutBox::new(
2955 node.node_id,
2956 rect,
2957 node.content_offset,
2958 data,
2959 children,
2960 ))
2961 }
2962
2963 Ok(LayoutTree::new(place(
2964 applier,
2965 node,
2966 Point { x: 0.0, y: 0.0 },
2967 )?))
2968}
2969
2970fn semantics_role_from_layout_box(layout_box: &LayoutBox) -> SemanticsRole {
2971 match &layout_box.node_data.kind {
2972 LayoutNodeKind::Subcompose => SemanticsRole::Subcompose,
2973 LayoutNodeKind::Spacer => SemanticsRole::Spacer,
2974 LayoutNodeKind::Unknown => SemanticsRole::Unknown,
2975 LayoutNodeKind::Button { .. } => SemanticsRole::Button,
2976 LayoutNodeKind::Layout => layout_box
2977 .node_data
2978 .modifier_slices()
2979 .text_content()
2980 .map(|text| SemanticsRole::Text {
2981 value: text.to_string(),
2982 })
2983 .unwrap_or(SemanticsRole::Layout),
2984 }
2985}
2986
2987fn build_semantics_node_from_layout_box(layout_box: &LayoutBox) -> SemanticsNode {
2988 let children = layout_box
2989 .children
2990 .iter()
2991 .map(build_semantics_node_from_layout_box)
2992 .collect();
2993
2994 semantics_node_from_parts(
2995 layout_box.node_id,
2996 semantics_role_from_layout_box(layout_box),
2997 collect_semantics_from_modifier(&layout_box.node_data.modifier),
2998 children,
2999 )
3000}
3001
3002fn layout_kind_from_metadata(_node_id: NodeId, info: &RuntimeNodeMetadata) -> LayoutNodeKind {
3003 match &info.role {
3004 SemanticsRole::Layout => LayoutNodeKind::Layout,
3005 SemanticsRole::Subcompose => LayoutNodeKind::Subcompose,
3006 SemanticsRole::Text { .. } => {
3007 LayoutNodeKind::Layout
3011 }
3012 SemanticsRole::Spacer => LayoutNodeKind::Spacer,
3013 SemanticsRole::Button => {
3014 let handler = info
3015 .button_handler
3016 .as_ref()
3017 .cloned()
3018 .unwrap_or_else(|| Rc::new(RefCell::new(|| {})));
3019 LayoutNodeKind::Button { on_click: handler }
3020 }
3021 SemanticsRole::Unknown => LayoutNodeKind::Unknown,
3022 }
3023}
3024
3025fn subtract_padding(constraints: Constraints, padding: EdgeInsets) -> Constraints {
3026 let horizontal = padding.horizontal_sum();
3027 let vertical = padding.vertical_sum();
3028 let min_width = (constraints.min_width - horizontal).max(0.0);
3029 let mut max_width = constraints.max_width;
3030 if max_width.is_finite() {
3031 max_width = (max_width - horizontal).max(0.0);
3032 }
3033 let min_height = (constraints.min_height - vertical).max(0.0);
3034 let mut max_height = constraints.max_height;
3035 if max_height.is_finite() {
3036 max_height = (max_height - vertical).max(0.0);
3037 }
3038 normalize_constraints(Constraints {
3039 min_width,
3040 max_width,
3041 min_height,
3042 max_height,
3043 })
3044}
3045
3046#[cfg(test)]
3047pub(crate) fn align_horizontal(alignment: HorizontalAlignment, available: f32, child: f32) -> f32 {
3048 match alignment {
3049 HorizontalAlignment::Start => 0.0,
3050 HorizontalAlignment::CenterHorizontally => ((available - child) / 2.0).max(0.0),
3051 HorizontalAlignment::End => (available - child).max(0.0),
3052 }
3053}
3054
3055#[cfg(test)]
3056pub(crate) fn align_vertical(alignment: VerticalAlignment, available: f32, child: f32) -> f32 {
3057 match alignment {
3058 VerticalAlignment::Top => 0.0,
3059 VerticalAlignment::CenterVertically => ((available - child) / 2.0).max(0.0),
3060 VerticalAlignment::Bottom => (available - child).max(0.0),
3061 }
3062}
3063
3064fn resolve_dimension(
3065 base: f32,
3066 explicit: DimensionConstraint,
3067 min_override: Option<f32>,
3068 max_override: Option<f32>,
3069 min_limit: f32,
3070 max_limit: f32,
3071) -> f32 {
3072 let mut min_bound = min_limit;
3073 if let Some(min_value) = min_override {
3074 min_bound = min_bound.max(min_value);
3075 }
3076
3077 let mut max_bound = if max_limit.is_finite() {
3078 max_limit
3079 } else {
3080 max_override.unwrap_or(max_limit)
3081 };
3082 if let Some(max_value) = max_override {
3083 if max_bound.is_finite() {
3084 max_bound = max_bound.min(max_value);
3085 } else {
3086 max_bound = max_value;
3087 }
3088 }
3089 if max_bound < min_bound {
3090 max_bound = min_bound;
3091 }
3092
3093 let mut size = match explicit {
3094 DimensionConstraint::Points(points) => points,
3095 DimensionConstraint::Fraction(fraction) => {
3096 if max_limit.is_finite() {
3097 max_limit * fraction.clamp(0.0, 1.0)
3098 } else {
3099 base
3100 }
3101 }
3102 DimensionConstraint::Unspecified => base,
3103 DimensionConstraint::Intrinsic(_) => base,
3106 };
3107
3108 size = clamp_dimension(size, min_bound, max_bound);
3109 size = clamp_dimension(size, min_limit, max_limit);
3110 size.max(0.0)
3111}
3112
3113fn clamp_dimension(value: f32, min: f32, max: f32) -> f32 {
3114 let mut result = value.max(min);
3115 if max.is_finite() {
3116 result = result.min(max);
3117 }
3118 result
3119}
3120
3121fn normalize_constraints(mut constraints: Constraints) -> Constraints {
3122 if constraints.max_width < constraints.min_width {
3123 constraints.max_width = constraints.min_width;
3124 }
3125 if constraints.max_height < constraints.min_height {
3126 constraints.max_height = constraints.min_height;
3127 }
3128 constraints
3129}
3130
3131#[cfg(test)]
3132#[path = "tests/layout_tests.rs"]
3133mod tests;